I know that, in the grand scope of things, this is a non-problem. But I still find it curious, and a little odd.
func a(_ p: UnsafePointer<UInt32>) {
print(p)
}
func b(_ p: UnsafeBufferPointer<UInt32>) {
print(p)
}
let testArray: [UInt32] = [1, 2, 3, 4]
a(testArray)
// 0x0000600000abcdef
b(testArray)
// error: cannot convert value of type '[UInt32]' to expected argument type 'UnsafeBufferPointer<UInt32>'
The only difference between UnsafePointer and UnsafeBufferPointer is that the buffer pointer carries an element count, right? So why is Array allowed to implicitly cast to UnsafePointer but not UnsafeBufferPointer?
Yes, of course, one can (and should) use withUnsafeBufferPointer. I know. I also know that Array is not guaranteed to have contiguous storage, and withUnsafeBufferPointer might cause a copy (though I'm not sure if this ever actually happens in the standard library or Foundation). But it still seems weird to me. Why convert one kind of unsafe pointer implicitly, while the other (arguably safer) kind requires a pretty wordy function invocation?
I suspect the answer might be "C interop weirdness", but if there's more to it I'd be interested to know.
That's pretty much it. All of the argument pointer conversions were intended for C interop, even though we didn't actually limit them to C functions, so they only support C types.
It's worth considering whether or not we might be able to restrict some of these C interop conversions to only apply to functions imported from C, to avoid confusion (and subtle sources of unsafety).
I’ve always pushed back on that because it means functions can’t be migrated from C to Swift. Though I guess we could say @exposeToC or whatever re-enables the conversions, when it comes to that.
To migrate to Swift, you would "simply" add an explicit overload for the cases where the conversion actually makes sense (but ideally you would provide a better API in Swift anyway--simply migrating existing unsafe pointer functions to Swift means that you're replacing the implementation without benefiting from safer interfaces).
An explicit marker could also be an option, of course.
I think it would be pretty reasonable to tie this up with a formalized cdecl as "this function has C language semantics (including both mangling/visibility for C and pointer conversions).”