[swift-evolution] [Draft] UnsafeRawPointer API

Andrew Trick atrick at apple.com
Fri Jun 24 21:56:59 CDT 2016

> On Jun 24, 2016, at 11:22 AM, Andrew Trick via swift-evolution <swift-evolution at swift.org> wrote:
>> On Jun 24, 2016, at 11:17 AM, L. Mihalkovic <laurent.mihalkovic at gmail.com <mailto:laurent.mihalkovic at gmail.com>> wrote:
>> I like the watch-what-you-wish-for warning of unsafeCast.
> I’ll try porting stdlib to the “UnsafeRawPointer.unsafeCast(to: T.Type)” syntax and see how bad it is.

I don't think there's a clear winner here. Let me enumerate some

Option (1) UnsafePointer<T>(cast: UnsafeRawPointer)

Option (2) UnsafePointer<T>(_: UnsafeRawPointer, to: T.self)

Option (3) UnsafeRawPointer.unsafeCast<T>(to: T.Type) -> UnsafePointer<T>

Option (4) unsafeCast(rawPointer: UnsafeRawPointer, to: T.self) -> UnsafePointer<T>

Option (3) is the most explicit and searchable, and forces
UnsafeRawPointer to be spelled out in the conversion (unless you
already have a raw pointer). I like this because conceptually, you
need to cast to a raw pointer before casting to a new pointee
type, and casting a raw pointer to a typed pointer carries important
semantics beyond simply converting to a typed pointer. The main problem
with Option (3) is that optional raw pointers can't be converted
naturally (without using `map`).

Another thing I'm a little nervous about is confusing a cast of the
pointer value with a cast of the pointee type:

  `unsafeBitCast(rawPtr, to: Int.self)`

is very different from

  `rawPtr.unsafeCast(to: Int.self)`

Does this need to be clarified? If so, we can go back to the
`toPointee` label that I proposed earlier.

With that in mind, Option(4) is starting to look pretty good.


Case 1: casting a raw pointer as an argument

func foo(_: UnsafePointer<A>)

let rawPtr = UnsafeRawPointer(...)

(1) foo(UnsafePointer(cast: rawPtr))

(2) foo(UnsafePointer(rawPtr, to: A.self))

(3) foo(rawPtr.unsafeCast(to: A.self))

(4) foo(unsafeCast(rawPointer: rawPtr, to: A.self))

Case 2: "recasting" a typed pointer argument

Note that typed pointer arguments are implicitly cast to raw pointer
arguments, so the conversion from PtrB to raw is implicit.

func foo(_: UnsafePointer<A>)

let ptrB = UnsafePointer<B>(...)

(1) foo(UnsafePointer(cast: ptrB))

(2) foo(UnsafePointer(ptrB, to: A.self))

(3) foo(UnsafeRawPointer(ptrB).unsafeCast(to: A.self))

(4) foo(unsafeCast(rawPointer: ptrB, to: A.self))

Case 3: Optional argument (only Option 3 is affected)

func nullableFoo(_: UnsafePointer<Int>?)

let ptrB: UnsafePointer<UInt>? = ...

(1) nullableFoo(UnsafePointer(cast: ptrB))

(2) nullableFoo(UnsafePointer(ptrB, to: A.self))

(3) nullableFoo(UnsafeRawPointer(ptrB).map { $0.unsafeCast(to: A.self) })

(4) nullableFoo(unsafeCast(rawPointer: ptrB, to: A.self))

Case 4: Return values

func foo() -> UnsafePointer<A>

func caller() -> UnsafePointer<B> { ...

(1) return UnsafePointer(cast: foo())

(2) return UnsafePointer(foo(), to: B.self)

(3) let rawPtr = UnsafeRawPointer(foo())
    return rawPtr.unsafeCast(to: B.self)

(4) return unsafeCast(rawPointer: foo(), to: B.self)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160624/fbd47f36/attachment.html>

More information about the swift-evolution mailing list