[swift-evolution] [Draft] UnsafeRawPointer API

Dave Abrahams dabrahams at apple.com
Mon Jun 27 17:35:53 CDT 2016


on Mon Jun 27 2016, Andrew Trick <atrick-AT-apple.com> wrote:

> I agree, this syntax works best, all considered:
>
> UnsafeRawPointer.cast(to: UnsafePointer<B>.Type)
>
>> On Jun 26, 2016, at 11:39 PM, Dave Abrahams <dabrahams at apple.com> wrote:
>> is better.  But I hate that the language doesn't give us a way to say
>> “don't deduce generic parameters here.”  This is the only syntax that
>> feels right, IMO:
>> 
>>    let p = UnsafePointer<Int>(r)
>
> FWIW: I prefer to avoid the angle brackets, but it's not a battle that
> needs to be fought over this feature. 

Then you should lobby for removing them from the language :-).  

The way we do lossless conversions in Swift is with a label-less init
that takes a single parameter.  When you do that, you spell out the
target type and follow it with parens. It doesn't make sense that it
should work differently for UnsafePointer<Int> than it does for Int.

> When experimenting with cast syntax, I found that passing type
> parameters as function arguments was much more readable than using
> generic type parameters, which I think obscure the signature. This
> will be especially true when '.self' goes away.
>
>>> Option (3) UnsafeRawPointer.unsafeCast<T>(to: T.Type) ->
>>> UnsafePointer<T>
>> 
>>    r.unsafeCast(to: Int.self)
>> 
>> I don't see adding “unsafe” to the name of the operation as adding
>> anything.  It isn't any more unsafe than other UnsafeRawPointer
>> operations.  Also, it reads like we're casting the raw pointer to an
>> Int, rather than to an UnsafePointer<Int>.
>
> Casting from a raw pointer to a typed pointer is only more dangerous
> than other raw pointer operations because it is the first step in this
> sequence of operations, which is undefined:
>
> ptrA = rawPtr.cast(to: UnsafePointer<A>.self)
> ptrA.initialize(with: A())
> ptrA.deinitialize()
>
> ptrB = rawPtr.cast(to: UnsafePointer<B>.self)
> ptrB.initialize(with: B())

But it's trivial to get undefined behavior without any of that.  Just:

  _ = rawPtr.load(UnsafePointer<NonTrivialType>.self)

boom.

>>  Also, how do you get an
>> UnsafeMutablePointer?
>
> UnsafeRawPointer casts to UnsafePointer<T>
> UnsafeMutableRawPointer casts to UnsafeMutablePointer<T>

OK.

>>> 
>>> Examples:
>>> 
>>> ---
>>> Case 1: casting a raw pointer as an argument
>> 
>> 
>> 
>> foo(rawPtr.cast(to: UnsafePointer<A>.self))
>> 
>>> ---
>>> Case 2: "recasting" a typed pointer argument
>>> 
>>> 
>> 
>> foo(UnsafeRawPointer(ptrB).cast(to: UnsafePointer<A>.self))
>> 
>> I don't believe in making these “double-hops” concise.
>> 
>>> ---
>>> Case 3: Optional argument (only Option 3 is affected)
>>> 
>> 
>> nullableFoo(UnsafeRawPointer(ptrB)?.cast(to: UnsafePointer<A>.self))
>> 
>> You do the above with a failable init on UnsafeRawPointer that takes an
>> optional UnsafePointer.
>> 
>>> ---
>>> Case 4: Return values
>>> 
>> 
>> return UnsafeRawPointer(foo()).cast(to: UnsafePointer<B>.self)
>> 
>> -- 
>> -Dave
>
> Yes, that works.
>
> -Andy

-- 
Dave


More information about the swift-evolution mailing list