> On Jun 24, 2016, at 11:22 AM, Andrew Trick via swift-evolution
> <[email protected]> wrote:
>
>> On Jun 24, 2016, at 11:17 AM, L. Mihalkovic <[email protected]
>> <mailto:[email protected]>> 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
options.
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.
Examples:
---
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)
-Andy_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution