The following swift program defines an enumeration called tempConverter with 2 cases - Fahrenheit & Celsius. That same enumeration also defines a method convert which takes a temperature value as a Double, and returns a C to F or F to C temperature conversion, depending on what the initialized value of tempConverter.self is. It also defines a method called switchScale which simply returns both Celsius & Fahrenheit conversions for the Double provided. When calling these methods & printing their results, I am getting a series of () characters outputted after the conversion values. Here's a link to a visual of the output I am seeing, reference this if you do not want to copy & run the code yourself.
Here's the code in its entirety, I really don't know why these () characters are being displayed, or how to remove them from the output.
Any help is appreciated!
(p.s) I know I spelt Fahrenheit wrong in the program, I have no excuse & am simply stupid. Carry on.
import Foundation
enum tempConverter{
case Celsius
case Farenheit
init(in scale: String){
self = .Celsius
scale.lowercased()
if scale.contains("c"){
self = .Celsius
}
else if scale.contains("f"){
self = .Farenheit
}
}
func convert(for temp: Double){
switch(self){
case .Celsius: print(temp, "c ->", (temp * 9)/5 + 32, "f")
break
case .Farenheit: print(temp, "f ->", (temp - 32) * 5 / 9, "c")
break
}
}
mutating func switchScale(){
switch(self){
case .Celsius:
self = .Farenheit
print(convert(for: temp))
break
case .Farenheit:
self = .Celsius
print(convert(for: temp))
break
}
}
}
var instance = tempConverter(in: "f")
var temp = 32.0
print(instance.convert(for: temp), instance.switchScale())
temp = 212.0
print(instance.convert(for: temp), instance.switchScale())
There is a lot going on with your code that I would change but to answer your specific question, the reason you are getting parentheses in your output is because you are printing a function.
struct SomeStruct {
func someFunc() {}
}
let s = SomeStruct()
print(s.someFunc()) // prints ()
You do that here:
print(instance.convert(for: temp)) // prints ()
What you see as output is that you are printing the returned value from the function call.
Functions that doesn't return a real value are said to return void and void can in swift be represented either with the keyword Void or by empty parentheses, ()
So in your case the function func convert(for temp: Double) returns void and this is printed as ()
You can actually declare the function to return void if you want to be extra clear (but you don't need to, the compiler understands you anyway) so
func convert(for temp: Double) { ... }
func convert(for temp: Double) -> Void { ... }
func convert(for temp: Double) -> () { ... }
all mean the same.
Off topic but maybe you mean for your function to return a Double so you could print that instead. Like this for example
func convert(for temp: Double) -> Double {
switch(self){
case .Celsius:
return temp * 9/5 + 32
case .Farenheit:
return (temp - 32) * 5 / 9
}
}
Related
I am building some classes and code that store and perform arithmetic on currency values. I was originally using Doubles, but converted to Decimal due to arithmetic errors.
I am trying to find the best way to run unit tests against functions working with Decimal type.
Consider position.totalCost is a Decimal type.
XCTAssertEqual(position.totalCost, 3571.6, accuracy: 0.01)
This code does not compile because Decimal does not conform to FloatingPoint. XCTAssertEqual requires parameters to be Doubles or Floats.
I got around this by doing the following:
XCTAssertTrue(position.totalCost == 3571.6)
Which does work, but if an error arises during the unit test, I get a vague message:
XCTAssertTrue failed rather than the more useful XCTAssertEqual failed: ("2.0") is not equal to ("1.0")
So using XCTAssertEqual is ideal.
Potential Options (as a novice, no clue which is better or viable)
Code my Position class to store all properties as Decimal but use computed properties to get and set them as Doubles.
Write a custom assertion that accepts Decimals. This is probably the most 'proper' path because the only issue I've encountered so far with using Decimals is that XCT assertions cannot accept them.
Write a goofy Decimal extension that will return a Double value. For whatever reason, there is no property or function in the Decimal class that returns a Double or Floag.
Don't convert Decimal to a floating point if you don't have to since it will result in a loss of precision. If you want to compare two Decimal values with some accuracy you can use Decimal.distance(to:) function like so:
let other = Decimal(35716) / Decimal(10) // 3571.6
let absoluteDistance = abs(position.totalCost.distance(to: other))
let accuracy = Decimal(1) / Decimal(100) // 0.01
XCTAssertTrue(absoluteDistance < accuracy)
You can write an extension on Decimal:
extension Decimal {
func isEqual(to other: Decimal, accuracy: Decimal) -> Bool {
abs(distance(to: other)).isLess(than: accuracy)
}
}
And then use it in your tests:
XCTAssertTrue(position.totalCost.isEqual(to: 3571.6, accuracy: 0.01))
This is likely good enough. However, to get better error messages in the case of a failing test would require writing an overload for XCTAssertEqual, which is actually a bit tricky because elements of XCTest are not publicly available.
However, it is possible to approximate the behaviour:
Firstly, we need some plumbing to evaluate assertions, this can more or less be lifted straight from swift-corelibs-xctest.
import Foundation
import XCTest
internal enum __XCTAssertionResult {
case success
case expectedFailure(String?)
case unexpectedFailure(Swift.Error)
var isExpected: Bool {
switch self {
case .unexpectedFailure: return false
default: return true
}
}
func failureDescription() -> String {
let explanation: String
switch self {
case .success: explanation = "passed"
case .expectedFailure(let details?): explanation = "failed: \(details)"
case .expectedFailure: explanation = "failed"
case .unexpectedFailure(let error): explanation = "threw error \"\(error)\""
}
return explanation
}
}
internal func __XCTEvaluateAssertion(testCase: XCTestCase, _ message: #autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line, expression: () throws -> __XCTAssertionResult) {
let result: __XCTAssertionResult
do {
result = try expression()
}
catch {
result = .unexpectedFailure(error)
}
switch result {
case .success: return
default:
let customMessage = message()
let description = customMessage.isEmpty ? result.failureDescription() : "\(result.failureDescription()) - \(customMessage)"
testCase.record(.init(
type: .assertionFailure,
compactDescription: description,
detailedDescription: nil,
sourceCodeContext: .init(
location: .init(filePath: String(describing: file), lineNumber: Int(line))
),
associatedError: nil,
attachments: [])
)
}
}
Now, for all of this to work, requires us to have access to the currently running XCTestCase, inside a global XCTAssert* function, which is not possible. Instead we can add our assert function in an extension.
extension XCTestCase {
func AssertEqual(
_ expression1: #autoclosure () throws -> Decimal,
_ expression2: #autoclosure () throws -> Decimal,
accuracy: #autoclosure () throws -> Decimal,
_ message: #autoclosure () -> String = "",
file: StaticString = #file,
line: UInt = #line
) {
__XCTEvaluateAssertion(testCase: self, message(), file: file, line: line) {
let lhs = try expression1()
let rhs = try expression2()
let acc = try accuracy()
guard lhs.isEqual(to: rhs, accuracy: acc) else {
return .expectedFailure("(\"\(lhs)\") is not equal to (\"\(rhs)\")")
}
return .success
}
}
}
All of which allows us to write our test cases as follows...
class MyTests: XCTestCase {
// etc
func test_decimal_equality() {
AssertEquals(position.totalCost, 3571.6, accuracy: 0.01)
}
}
And if the assertion fails, the test case will fail, with the message: ("3571.5") is not equal to ("3571.6") at the correct line.
We also cannot call our function XCTAssertEquals, as this will override all the global assert functions.
You milage may vary, but once you have the plumbing in place, this allows you to write bespoke custom assertions for your test suite.
Do you really need to specify the accuracy of 0.01?
Because if you omit this argument, it compiles just fine.
struct Position {
let totalCost: Decimal
}
let position = Position(totalCost: 3571.6)
//passes
XCTAssertEqual(position.totalCost, 3571.6)
// XCTAssertEqual failed: ("3571.6") is not equal to ("3571.61")
XCTAssertEqual(position.totalCost, 3571.61)
I want to test my function that takes a string, a returns all the pairs of characters as an array s.t.
func pairsOfChars(_ s: String) -> [(Character,Character)] {
let strArray = Array(s)
var outputArray = [(Character,Character)]()
for i in 0..<strArray.count - 1 {
for j in i + 1..<strArray.count {
outputArray.append( (strArray[i], strArray[j]) )
}
}
return outputArray
}
So I want to create a suite of tests using XCTestCase. I usually use XCTestCase and XCTAssertEqual but these are only appropriate for C scalar types. This means that the following test case returns an error:
class pairsTests: XCTestCase {
func testNaive() {
measure {
XCTAssertEqual( pairsOfChars("abc") , [(Character("a"),Character("b")),(Character("a"),Character("c")),(Character("b"),Character("c")) ] )
}
}
}
I could convert to a string, but I'm thinking there is a better solution.
How can I test an output of an array of pairs of characters [(Character,Character)]
Your notion of a nonscalar is a total red herring. The problem is one of equatability.
How can I test an output of an array of pairs of characters [(Character,Character)]
You can't, because there is no default notion of what it would mean to equate two such arrays. This is the old "tuples of Equatable are not Equatable" problem (https://bugs.swift.org/browse/SR-1222) which still rears its head with arrays. The == operator works on tuples by a kind of magic, but they are still not formally Equatable.
You could define equatability of arrays of character pairs yourself:
typealias CharPair = (Character,Character)
func ==(lhs:[CharPair], rhs:[CharPair]) -> Bool {
if lhs.count != rhs.count {
return false
}
let zipped = zip(lhs,rhs)
return zipped.allSatisfy{$0 == $1}
}
Alternatively, have your pairsOfChars return something that is more easily made equatable, such as an array of a struct for which Equatable is defined.
For example:
struct CharacterPair : Equatable {
let c1:Character
let c2:Character
// in Swift 4.2 this next bit is not needed
static func ==(lhs:CharacterPair, rhs:CharacterPair) -> Bool {
return lhs.c1 == rhs.c1 && lhs.c2 == rhs.c2
}
}
func pairsOfChars(_ s: String) -> [CharacterPair] {
let strArray = Array(s)
var outputArray = [CharacterPair]()
for i in 0..<strArray.count - 1 {
for j in i + 1..<strArray.count {
outputArray.append(CharacterPair(c1:strArray[i],c2:strArray[j]))
}
}
return outputArray
}
You would then rewrite the test to match:
XCTAssertEqual(
pairsOfChars("abc"),
[CharacterPair(c1:Character("a"),c2:Character("b")),
CharacterPair(c1:Character("a"),c2:Character("c")),
CharacterPair(c1:Character("b"),c2:Character("c"))]
)
I understand the reasons why the Character class doesn't support toUpper() and toLower() but my use case is not for language purposes. Furthermore, I do not wish to revert to NSString.
So what's the fastest way to convert a character to upper case or lower case using Swift 4?
// Is there something better than this?
extension Character {
func toLower() -> Character {
return String(self).lowercased().first!
}
}
Use the uppercase2() below if you only need to uppercase the first char. It’s a 5x speed up over uppercasing the entire string.
import Foundation
// too slow, maybe with some bitwise operations could get faster 🤷♀️
func uppercase(_ string: String) -> Character? {
let key: Int8 = string.utf8CString[0]
guard key>0, key<127, let c = Unicode.Scalar(Int(key >= 97 ? key - Int8(32) : key)) else { return nil }
return Character(c)
}
// winner but using internal _core stuff
func uppercase2(_ string: String) -> Character? {
guard let key = string._core.asciiBuffer?[0] else { return nil }
return Character(Unicode.Scalar(key >= 97 ? key - 32 : key)) // use < + to lowercase
}
func measure(times: Int, task: ()->()){
let start1 = CFAbsoluteTimeGetCurrent()
for _ in 1..<times {
task()
}
print(CFAbsoluteTimeGetCurrent() - start1)
}
print("😀".uppercased().first as Any) // Optional("😀")
print(uppercase("😀") as Any) // nil
print(uppercase2("😀") as Any) // nil
measure(times: 10_000_000) { _ = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".uppercased().first } // 4.17883902788162
measure(times: 10_000_000) { _ = uppercase("ABCDEFGHIJKLMNOPQRSTUVWXYZ") } // 4.91275697946548
measure(times: 10_000_000) { _ = uppercase2("ABCDEFGHIJKLMNOPQRSTUVWXYZ") } // 0.720575034618378
In a 10 million run, Apple’s uppercased ran 148x times faster than the code at the bottom of this post, even with force-unwrap. I’ll leave it for comedic purposes.
Their approach is of course, way lower level. See lowercased(). They check for an internal asciiBuffer and then use an _asciiUpperCaseTable.
My understanding is that if the original String is already a Swift String, it will be represented by a StringCore class which is already optimized to deal with ASCII characters at a low level. Thus, you won’t be able to beat the uppercase function of Swift.
So, kind of an answer: the fastest way is to use the regular uppercase() function.
I'm assuming that “my use-case is not for language purposes” means I’m only using ASCII. The advantage that this provides is that UTF-8 and ASCII share the same scalar code, so upper/lowercasing implies subtracting or adding a fixed number.
import Foundation
print("a".unicodeScalars.first!.value) // 97
print("A".unicodeScalars.first!.value) // 65
let uppercase = String("abcde".flatMap {
guard let char = $0.unicodeScalars.first,
let uppercased = Unicode.Scalar(char.value - UInt32(97 - 65))
else {
return nil
}
return Character(uppercased)
})
print(uppercase) // ABCDE
I have a dictionary of formulas (in closures) that I now what to use in a function to calculate some results.
var formulas: [String: (Double, Double) -> Double] = [
"Epley": {(weightLifted, repetitions) -> Double in return weightLifted * (1 + (repetitions)/30)},
"Brzychi": {(weightLifted, repetitions) -> Double in return weightLifted * (36/(37 - repetitions)) }]
Now I'm trying to write a function that will get the correct formula from the dictionary based on the name, calculate the result, and return it.
func calculateOneRepMax(weightLifted: Double, repetitions: Double) -> Double {
if let oneRepMax = formulas["Epley"] { $0, $1 } <-- Errors here because I clearly don't know how to do this part
return oneRepMax
}
var weightlifted = 160
var repetitions = 2
let oneRepMax = Calculator.calculateOneRepMax(weightlifted, repetitions)
Now Xcode is giving me errors like 'Consecutive statements on a line must be separated by a ';' which tells me the syntax I'm trying to use isn't correct.
On a side note, I wasn't sure if I should use a dictionary for this but after a lot of homework I'm confident it's the correct choice considering I need to iterate through it to get the values when I need them and I need to know the number of key/value pairs so I can do things like display their names in a Table View.
I've searched far and wide for answers, read Apple's documentation over and over and I'm really stuck.
Thanks
formulas["Epley"] returns an optional closure which needs to be
unwrapped before you can apply it to the given numbers. There are several options you can choose from:
Optional binding with if let:
func calculateOneRepMax(weightLifted: Double, repetitions: Double) -> Double {
if let formula = formulas["Epley"] {
return formula(weightLifted, repetitions)
} else {
return 0.0 // Some appropriate default value
}
}
This can be shortened with optional chaining and the
nil-coalescing operator ??:
func calculateOneRepMax(weightLifted: Double, repetitions: Double) -> Double {
return formulas["Epley"]?(weightLifted, repetitions) ?? 0.0
}
If a non-existing key should be treated as a fatal error instead
of returning a default value, then guard let would be
appropriate:
func calculateOneRepMax(weightLifted: Double, repetitions: Double) -> Double {
guard let formula = formulas["Epley"] else {
fatalError("Formula not found in dictionary")
}
return formula(weightLifted, repetitions)
}
I'm doing a bunch of BLE in iOS, which means lots of tight packed C structures being encoded/decoded as byte packets. The following playground snippets illustrate what I'm trying to do generically.
import Foundation
// THE PROBLEM
struct Thing {
var a:UInt8 = 0
var b:UInt32 = 0
var c:UInt8 = 0
}
sizeof(Thing) // --> 9 :(
var thing = Thing(a: 0x42, b: 0xDEADBEAF, c: 0x13)
var data = NSData(bytes: &thing, length: sizeof(Thing)) // --> <42000000 afbeadde 13> :(
So given a series of fields of varying size, we don't get the "tightest" packing of bytes. Pretty well known and accepted. Given my simple structs, I'd like to be able to arbitrarily encode the fields back to back with no padding or alignment stuff. Relatively easy actually:
// ARBITRARY PACKING
var mirror = Mirror(reflecting: thing)
var output:[UInt8] = []
mirror.children.forEach { (label, child) in
switch child {
case let value as UInt32:
(0...3).forEach { output.append(UInt8((value >> ($0 * 8)) & 0xFF)) }
case let value as UInt8:
output.append(value)
default:
print("Don't know how to serialize \(child.dynamicType) (field \(label))")
}
}
output.count // --> 6 :)
data = NSData(bytes: &output, length: output.count) // --> <42afbead de13> :)
Huzzah! Works as expected. Could probably add a Class around it, or maybe a Protocol extension and have a nice utility. The problem I'm up against is the reverse process:
// ARBITRARY DEPACKING
var input = output.generate()
var thing2 = Thing()
"\(thing2.a), \(thing2.b), \(thing2.c)" // --> "0, 0, 0"
mirror = Mirror(reflecting:thing2)
mirror.children.forEach { (label, child) in
switch child {
case let oldValue as UInt8:
let newValue = input.next()!
print("new value for \(label!) would be \(newValue)")
// *(&child) = newValue // HOW TO DO THIS IN SWIFT??
case let oldValue as UInt32: // do little endian
var newValue:UInt32 = 0
(0...3).forEach {
newValue |= UInt32(input.next()!) << UInt32($0 * 8)
}
print("new value for \(label!) would be \(newValue)")
// *(&child) = newValue // HOW TO DO THIS IN SWIFT??
default:
print("skipping field \(label) of type \(child.dynamicType)")
}
}
Given an unpopulated struct value, I can decode the byte stream appropriately, figure out what the new value would be for each field. What I don't know how to do is to actually update the target struct with the new value. In my example above, I show how I might do it with C, get the pointer to the original child, and then update its value with the new value. I could do it easily in Python/Smalltalk/Ruby. But I don't know how one can do that in Swift.
UPDATE
As suggested in comments, I could do something like the following:
// SPECIFIC DEPACKING
extension GeneratorType where Element == UInt8 {
mutating func _UInt8() -> UInt8 {
return self.next()!
}
mutating func _UInt32() -> UInt32 {
var result:UInt32 = 0
(0...3).forEach {
result |= UInt32(self.next()!) << UInt32($0 * 8)
}
return result
}
}
extension Thing {
init(inout input:IndexingGenerator<[UInt8]>) {
self.init(a: input._UInt8(), b: input._UInt32(), c: input._UInt8())
}
}
input = output.generate()
let thing3 = Thing(input: &input)
"\(thing3.a), \(thing3.b), \(thing3.c)" // --> "66, 3735928495, 19"
Basically, I move the various stream decoding methods to byte stream (i.e. GeneratorType where Element == UInt8), and then I just have to write an initializer that strings those off in the same order and type the struct is defined as. I guess that part, which is essentially "copying" the structure definition itself (and therefore error prone), is what I had hoped to use some sort of introspection to handle. Mirrors are the only real Swift introspection I'm aware of, and it seems pretty limited.
As discussed in the comments, I suspect this is over-clever. Swift includes a lot of types not friendly to this approach. I would focus instead on how to make the boilerplate as easy as possible, without worrying about eliminating it. For example, this is very sloppy, but is in the direction I would probably go:
Start with some helper packer/unpacker functions:
func pack(values: Any...) -> [UInt8]{
var output:[UInt8] = []
for value in values {
switch value {
case let i as UInt32:
(0...3).forEach { output.append(UInt8((i >> ($0 * 8)) & 0xFF)) }
case let i as UInt8:
output.append(i)
default:
assertionFailure("Don't know how to serialize \(value.dynamicType)")
}
}
return output
}
func unpack<T>(bytes: AnyGenerator<UInt8>, inout target: T) throws {
switch target {
case is UInt32:
var newValue: UInt32 = 0
(0...3).forEach {
newValue |= UInt32(bytes.next()!) << UInt32($0 * 8)
}
target = newValue as! T
case is UInt8:
target = bytes.next()! as! T
default:
// Should throw an error here probably
assertionFailure("Don't know how to deserialize \(target.dynamicType)")
}
}
Then just call them:
struct Thing {
var a:UInt8 = 0
var b:UInt32 = 0
var c:UInt8 = 0
func encode() -> [UInt8] {
return pack(a, b, c)
}
static func decode(bytes: [UInt8]) throws -> Thing {
var thing = Thing()
let g = anyGenerator(bytes.generate())
try unpack(g, target: &thing.a)
try unpack(g, target: &thing.b)
try unpack(g, target: &thing.c)
return thing
}
}
A little more thought might be able to make the decode method a little less repetitive, but this is still probably the way I would go, explicitly listing the fields you want to encode rather than trying to introspect them. As you note, Swift introspection is very limited, and it may be that way for a long time. It's mostly used for debugging and logging, not logic.
I have tagged Rob's answer is the official answer. But I'd thought I'd share what I ended up doing as well, inspired by the comments and answers.
First, I fleshed out my "Problem" a little to include a nested structure:
struct Inner {
var ai:UInt16 = 0
var bi:UInt8 = 0
}
struct Thing {
var a:UInt8 = 0
var b:UInt32 = 0
var inner = Inner()
var c:UInt8 = 0
}
sizeof(Thing) // --> 12 :(
var thing = Thing(a: 0x42, b: 0xDEADBEAF, inner: Inner(ai: 0x1122, bi: 0xDD), c: 0x13)
var data = NSData(bytes: &thing, length: sizeof(Thing)) // --> <42000000 afbeadde 2211dd13> :(
For Arbitrary Packing, I stuck with the same generic approach:
protocol Packable {
func packed() -> [UInt8]
}
extension UInt8:Packable {
func packed() -> [UInt8] {
return [self]
}
}
extension UInt16:Packable {
func packed() -> [UInt8] {
return [(UInt8((self >> 0) & 0xFF)), (UInt8((self >> 8) & 0xFF))]
}
}
extension UInt32:Packable {
func packed() -> [UInt8] {
return [(UInt8((self >> 0) & 0xFF)), (UInt8((self >> 8) & 0xFF)), (UInt8((self >> 16) & 0xFF)), (UInt8((self >> 24) & 0xFF))]
}
}
extension Packable {
func packed() -> [UInt8] {
let mirror = Mirror(reflecting:self)
var bytes:[UInt8] = []
mirror.children.forEach { (label, child) in
switch child {
case let value as Packable:
bytes += value.packed()
default:
print("Don't know how to serialize \(child.dynamicType) (field \(label))")
}
}
return bytes
}
}
Being able to "pack" things is as easy adding them to the Packable protocol and telling them to pack themselves. For my cases above, I only need 3 different types of signed integers, but one could add lots more. For example, in my own code, I have some Enums derived from UInt8 which I added the packed method to.
extension Thing:Packable { }
extension Inner:Packable { }
var output = thing.packed()
output.count // --> 9 :)
data = NSData(bytes: &output, length: output.count) // --> <42afbead de2211dd 13> :)
To be able to unpack stuff, I came up with a little bit of support:
protocol UnpackablePrimitive {
static func unpack(inout input:IndexingGenerator<[UInt8]>) -> Self
}
extension UInt8:UnpackablePrimitive {
static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt8 {
return input.next()!
}
}
extension UInt16:UnpackablePrimitive {
static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt16 {
return UInt16(input.next()!) | (UInt16(input.next()!) << 8)
}
}
extension UInt32:UnpackablePrimitive {
static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt32 {
return UInt32(input.next()!) | (UInt32(input.next()!) << 8) | (UInt32(input.next()!) << 16) | (UInt32(input.next()!) << 24)
}
}
With this, I can then add initializers to my high level structures, e.g.
extension Inner:Unpackable {
init(inout packed bytes:IndexingGenerator<[UInt8]>) {
self.init(ai: UInt16.unpack(&bytes), bi: UInt8.unpack(&bytes))
}
}
extension Thing:Unpackable {
init(inout packed bytes:IndexingGenerator<[UInt8]>) {
self.init(a: UInt8.unpack(&bytes), b: UInt32.unpack(&bytes), inner: Inner(packed:&bytes), c: UInt8.unpack(&bytes))
}
}
What I liked about this is that these initializers call the default initializer in the same order and types as the structure is defined. So if the structure changes in type or order, I have to revisit the (packed:) initializer. The kids a bit long, but not too.
What I didn't like about this, was having to pass the inout everywhere. I'm honestly not sure what the value is of value based generators, since passing them around you almost always want to share state. Kind of the whole point of reifying an object that captures the position of a stream of data, is to be able to share it. I also don't like having to specify IndexingGenerator directly, but I imagine there's some fu magic that would make that less specific and still work, but I'm not there yet.
I did play with something more pythonic, where I return a tuple of the type and the remainder of a passed array (rather than a stream/generator), but that wasn't nearly as easy to use at the top level init level.
I also tried putting the static methods as extensions on byte based generators, but you have to use a function (would rather have used a computed var with side effects) there whose name doesn't match a type, so you end up with something like
self.init(a: bytes._UInt8(), b: bytes._UInt32(), inner: Inner(packed:&bytes), c: bytes._UInt8())
This is shorter, but doesn't put the type like functions next to the argument names. And would require all kinds of application specific method names to be added as well as one extended the set of UnpackablePrimitives.