Generic question

Is there any advantage to doing this:

func test1<Integer: FixedWidthInteger>(_ b: [UInt8], as: Integer.Type) -> Integer {
    let r = b.withUnsafeBytes { $0.baseAddress!.bindMemory(to: Integer.self, capacity: 1) }
    return r.pointee
}
do {
    let i8 = test1([1,0,0,0,0,0,0,0], as: UInt8.self)
    print(type(of: i8), i8)
    let i32 = test1([1,0,0,0,0,0,0,0], as: UInt32.self)
    print(type(of: i32), i32)
}

vs this?

func test1<Integer: FixedWidthInteger>(_ b: [UInt8]) -> Integer {
    let r = b.withUnsafeBytes { $0.baseAddress!.bindMemory(to: Integer.self, capacity: 1) }
    return r.pointee
}

do {
    let i8 = test1([1,0,0,0,0,0,0,0]) as UInt8
    print(type(of: i8), i8)
    let i32 = test1([1,0,0,0,0,0,0,0]) as UInt32
    print(type(of: i32), i32)
}

I'm simply referring to the use of the Type parameter in the first example.

I think I was thrown by the definition of bindMemory, which does this sort of. But I now see that it returns a pointer to the type, and not the type itself, so I imagine that's why its needed in that case. Probably in my case above (yes, its a strawman example) the second way is fine. Yes? No? Who knows?

There's no difference in the generated code, but the first form forces clients to be explicit about what type they're using, while the second allows it to be inferred from context. For some APIs, like bindMemory(to:capacity:), the cost of getting it wrong is bad enough that the API authors decided it was important for clients to be explicit.

2 Likes

Thanks!

i always wondered, why isn’t it allowed to specialize functions with the <> syntax?

There's another thread that ended up discussing that just now: Future: On value-based generic arguments for functions - #8 by jrose.

Oh, there is one place in which there is different behavior, not in the examples you wrote but in something very similar. I think this can only come up using classes or @objc protocols today:

func test<SomeView: UIView>(_ type: SomeView.Type) {
  print(UIView.self)
  print(SomeView.self)
  print(type)
}

let type: UIControl.Type = UIButton.self
test(type)
// UIView
// UIControl
// UIButton

Notice how the static type becomes the generic parameter, but the dynamic type is still available if you have an explicit argument.

1 Like

Do you mean like this?

let i8 = test1<UInt8>([1,0,0,0,0,0,0,0])

I guess Jordan has answered this; just check to see if I understand the question.

2 Likes