[Draft] UnsafeRawPointer API

I agree, this syntax works best, all considered:

UnsafeRawPointer.cast(to: UnsafePointer<B>.Type)

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. 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())

Also, how do you get an
UnsafeMutablePointer?

UnsafeRawPointer casts to UnsafePointer<T>
UnsafeMutableRawPointer casts to UnsafeMutablePointer<T>

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

···

On Jun 26, 2016, at 11:39 PM, Dave Abrahams <dabrahams@apple.com> wrote:

Regards
(From mobile)

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)

The problem with this one is that T can be deduced based on type
context. I think we ought to move away from that for operations like
this one.

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

I think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

   let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

   let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a sensible thing to do. I guess that means it is more 'noguaranteeexplicitorimpliedapplied' in the sense that it will like mechanically work, even if it produce an aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something along the lines of 'wrappedType', which lookes a little less balerina-ish than pointee.....

···

On Jun 27, 2016, at 8:39 AM, Dave Abrahams <dabrahams@apple.com> wrote:
on Fri Jun 24 2016, Andrew Trick <atrick-AT-apple.com> wrote:

On Jun 24, 2016, at 11:22 AM, Andrew Trick via swift-evolution >>> <swift-evolution@swift.org> wrote:

On Jun 24, 2016, at 11:17 AM, L. Mihalkovic >>>> <laurent.mihalkovic@gmail.com >>>> <mailto:laurent.mihalkovic@gmail.com>> wrote:

Also, how do you get an
UnsafeMutablePointer?

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

This one won't read correctly for the same reasons as #3.

   r.cast(to: UnsafePointer<Int>.self)

works better for me than any of the alternatives given our inability to
get the One True Syntax.

---
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).

Huh? I'm confused here. What you wrote looks like it's intended to be
a regular method, in which case of course invoking it would require a raw
pointer and wouldn't force you to write UnsafeRawPointer out anywhere.

The only way it could force you to write UnsafeRawPointer would be if it
was a static method, but in that case it has too few arguments.

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`).

r ?? someExpressionUsing(r!)

best I can do.

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?

Yes!

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

Use sites! (yay)...

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))

foo(rawPtr.cast(to: UnsafePointer<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))

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)

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))

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

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)

return UnsafeRawPointer(foo()).cast(to: UnsafePointer<B>.self)

IMO-ly y'rs,

--
-Dave

Hi Andy,

Everything is clear now, thank you!

Initializing via a typed pointer, in addition to changing the temporal memory state, also imposes a type on the allocated memory for the entire lifetime of the memory itself, from allocation to deallocation.

I see. Given that UnsafeMutablePoiner.initialize() has this very
important difference in semantics, did you consider reflecting it in
the name? Something like '.bindTypeAndInitialize()' -- but I'm sure a
better wording is possible.

Yes, I did consider that. I’m still open to it--maybe ‘.typedInitialize(with:). But...

(1) It’s awkward. The developer isn’t interested in binding the type at that point. It’s just a side effect of the way their unsafe pointer is being used.

(2) It would imply that the ‘.bindAndInitialize' entry point is the only way to bind the type of allocated memory. But once you have a typed pointer, it’s easy to initialize memory via a simple assignment:
ptrToA[0] = A() // where A is trivial
If ptrToA was in an uninitialized state, then that also binds the type.

It would be good to call this out in the proposal (I did not get this
part from the clarifications that you posted this morning.) So the
rule is that every typed store binds the type?

Instead, I tried to focus on discouraging the unsafe pointer cast that leads to this situation. The important thing is that we have an alternate “safe” API so that most developers just don’t need to think about it.

That's a good goal.

Dmitri

···

On Tue, Jun 28, 2016 at 2:17 PM, Andrew Trick <atrick@apple.com> wrote:

On Jun 28, 2016, at 1:53 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
On Tue, Jun 28, 2016 at 1:02 PM, Andrew Trick <atrick@apple.com> wrote:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/

Any gripes about this syntax?

let ptrB = UnsafeRawPointer(ptrA).cast(to: UnsafePointer<B>.Type)

It meets the goal of being perfectly explicit. We can add convenience APIs for certain cases later.

-Andy

···

On Jun 27, 2016, at 1:52 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

  let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

  let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a sensible thing to do. I guess that means it is more 'noguaranteeexplicitorimpliedapplied' in the sense that it will like mechanically work, even if it produce an aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something along the lines of 'wrappedType', which lookes a little less balerina-ish than pointee.....

Regards
(From mobile)

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)

The problem with this one is that T can be deduced based on type
context. I think we ought to move away from that for operations like
this one.

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

I think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

   let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

   let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a
sensible thing to do.

Just like most of the other operations on UnsafeRawPointer, which is my
point.

I guess that means it is more 'noguaranteeexplicitorimpliedapplied' in
the sense that it will like mechanically work, even if it produce an
aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something
along the lines of 'wrappedType', which lookes a little less
balerina-ish than pointee.....

A pointer does not wrap its pointee.

···

on Mon Jun 27 2016, "L. Mihalkovic" <laurent.mihalkovic-AT-gmail.com> wrote:

On Jun 27, 2016, at 8:39 AM, Dave Abrahams <dabrahams@apple.com> wrote:
on Fri Jun 24 2016, Andrew Trick <atrick-AT-apple.com> wrote:

On Jun 24, 2016, at 11:22 AM, Andrew Trick via swift-evolution >>>> <swift-evolution@swift.org> wrote:

On Jun 24, 2016, at 11:17 AM, L. Mihalkovic >>>>> <laurent.mihalkovic@gmail.com >>>>> <mailto:laurent.mihalkovic@gmail.com>> wrote:

Also, how do you get an
UnsafeMutablePointer?

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

This one won't read correctly for the same reasons as #3.

   r.cast(to: UnsafePointer<Int>.self)

works better for me than any of the alternatives given our inability to
get the One True Syntax.

---
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).

Huh? I'm confused here. What you wrote looks like it's intended to be
a regular method, in which case of course invoking it would require a raw
pointer and wouldn't force you to write UnsafeRawPointer out anywhere.

The only way it could force you to write UnsafeRawPointer would be if it
was a static method, but in that case it has too few arguments.

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`).

r ?? someExpressionUsing(r!)

best I can do.

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?

Yes!

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

Use sites! (yay)...

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))

foo(rawPtr.cast(to: UnsafePointer<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))

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)

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))

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

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)

return UnsafeRawPointer(foo()).cast(to: UnsafePointer<B>.self)

IMO-ly y'rs,

--
-Dave

--
Dave

Aside from the fact that it doesn't compile? (s/Type/self/) ;-)

No gripes. I think I suggested it.

···

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

On Jun 27, 2016, at 1:52 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

  let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

  let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a
sensible thing to do. I guess that means it is more
'noguaranteeexplicitorimpliedapplied' in the sense that it will like
mechanically work, even if it produce an aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something
along the lines of 'wrappedType', which lookes a little less
balerina-ish than pointee.....

Any gripes about this syntax?

let ptrB = UnsafeRawPointer(ptrA).cast(to: UnsafePointer<B>.Type)

--
Dave

I agree, this syntax works best, all considered:

UnsafeRawPointer.cast(to: UnsafePointer<B>.Type)

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.

···

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

On Jun 26, 2016, at 11:39 PM, Dave Abrahams <dabrahams@apple.com> wrote:

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

Any gripes about this syntax?

let ptrB = UnsafeRawPointer(ptrA).cast(to: UnsafePointer<B>.Type)

Aside from the fact that it doesn't compile? (s/Type/self/) ;-)

Sorry, I keep converting between decl/use style and forgetting to update that.

No gripes. I think I suggested it.

I was responding to LM, and the rest of the list…

Andy

···

On Jun 27, 2016, at 3:27 PM, Dave Abrahams <dabrahams@apple.com> wrote:

Aside from the fact that it doesn't compile? (s/Type/self/) ;-)

Sorry, I keep converting between decl/use style and forgetting to update that.

No gripes. I think I suggested it.

I was responding to LM, and the rest of the list…

Andy

···

On Jun 27, 2016, at 3:27 PM, Dave Abrahams <dabrahams@apple.com> wrote:

Regards
LM
(From mobile)

···

On Jun 28, 2016, at 12:18 AM, Andrew Trick <atrick@apple.com> wrote:

On Jun 27, 2016, at 1:52 PM, L. Mihalkovic <laurent.mihalkovic@gmail.com> wrote:

think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

  let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

  let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a sensible thing to do. I guess that means it is more 'noguaranteeexplicitorimpliedapplied' in the sense that it will like mechanically work, even if it produce an aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something along the lines of 'wrappedType', which lookes a little less balerina-ish than pointee.....

Any gripes about this syntax?

let ptrB = UnsafeRawPointer(ptrA).cast(to: UnsafePointer<B>.Type)

It meets the goal of being perfectly explicit. We can add convenience APIs for certain cases later.

-Andy

I have to say, there are many situations when writing java code where i wished List<Int>.class existed.. instead I'd resort to xxx(List.class, Int.class) or to generic reflection on a abstract type token.
So this DEFINITELY floats my boat!!!! As you say, it is the most accurate depiction of what truly happens.

Regards
LM
(From mobile)

Regards
(From mobile)

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)

The problem with this one is that T can be deduced based on type
context. I think we ought to move away from that for operations like
this one.

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

I think you mean T.Type, not T.self, because this looks like a declaration.

To evaluate, you have to look at the use-site:

  let p = UnsafePointer(r, to: Int.self)

I don't find “to” to be descriptive enough. Maybe

toType

  let p = UnsafePointer(r, pointee: Int.self)

I find pointee a total aberation :)

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)

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.

It is unsafe in the sense that there are no guarantees that it is a
sensible thing to do.

Just like most of the other operations on UnsafeRawPointer, which is my
point.

I guess that means it is more 'noguaranteeexplicitorimpliedapplied' in
the sense that it will like mechanically work, even if it produce an
aberation as a result

Also, it reads like we're casting the raw pointer to an
Int, rather than to an UnsafePointer<Int>.

Really good one... But then instead of 'to' or 'pointee', something
along the lines of 'wrappedType', which lookes a little less
balerina-ish than pointee.....

A pointer does not wrap its pointee.

Mix a->b & from b
  let p = UnsafePointer(r, pointee: Int.self)
  let p = UnsafePointer(r, wrappedType: Int.self)

Purely a->b
  let p = UnsafePointer(r, toObjectOfType: Int.self)
  let p = UnsafePointer(r, targetType: Int.self)
  let p = UnsafePointer(r, to: Int.self)
  let p = UnsafePointer(r, toType: Int.self)
  let p = UnsafePointer(r, destinationType: Int.self)

You are of course absolutely right about wrappedType :)

I just think (for no other excuse than years of c) that when i think about a pointer i think of it directionally. And my unease comes from pointee suddenly shifting (for me) the view point: i suddenly have to shift to seeing the world from the other side. All the words i was trying (with the exception of wrappedType which i kept in the first group) share the FromSourceToDestination connotation that i implicitly associate with pointers. But this is just me and this is purely subjective. Maybe it is time i break this mental model... I still find pointee a little too Bolshoi for my taste (nothing i wont get used to though).

···

On Jun 28, 2016, at 12:25 AM, Dave Abrahams <dabrahams@apple.com> wrote:

on Mon Jun 27 2016, "L. Mihalkovic" <laurent.mihalkovic-AT-gmail.com> wrote:

On Jun 27, 2016, at 8:39 AM, Dave Abrahams <dabrahams@apple.com> wrote:
on Fri Jun 24 2016, Andrew Trick <atrick-AT-apple.com> wrote:

On Jun 24, 2016, at 11:22 AM, Andrew Trick via swift-evolution >>>>> <swift-evolution@swift.org> wrote:

On Jun 24, 2016, at 11:17 AM, L. Mihalkovic >>>>>> <laurent.mihalkovic@gmail.com >>>>>> <mailto:laurent.mihalkovic@gmail.com>> wrote:

Also, how do you get an
UnsafeMutablePointer?

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

This one won't read correctly for the same reasons as #3.

  r.cast(to: UnsafePointer<Int>.self)

works better for me than any of the alternatives given our inability to
get the One True Syntax.

---
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).

Huh? I'm confused here. What you wrote looks like it's intended to be
a regular method, in which case of course invoking it would require a raw
pointer and wouldn't force you to write UnsafeRawPointer out anywhere.

The only way it could force you to write UnsafeRawPointer would be if it
was a static method, but in that case it has too few arguments.

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`).

r ?? someExpressionUsing(r!)

best I can do.

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?

Yes!

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

Use sites! (yay)...

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))

foo(rawPtr.cast(to: UnsafePointer<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))

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)

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))

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

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)

return UnsafeRawPointer(foo()).cast(to: UnsafePointer<B>.self)

IMO-ly y'rs,

--
-Dave

--
Dave

Well, I’m focussing on the first initialization as a given type... I thought that explaining the rule in terms of binding allocated memory provided a simpler mental model, but it opens up questions once you try to pick it apart.

I changed the proposal so that "binding" a type is purely conceptual, not part of a formal memory model. I added the following formal rule to that section of the proposal instead:

A sequence of two memory operations to the same location violates strict aliasing under the following conditions:
- both operations access memory via a typed pointer
- the memory access types are unrelated
- at least one of the memory operations is a write
- there exists no intervening write to the same memory via a raw pointer

I updated the proposal under review with a related discussion and examples:

-Andy

···

On Jun 28, 2016, at 6:54 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

On Tue, Jun 28, 2016 at 2:17 PM, Andrew Trick <atrick@apple.com> wrote:

On Jun 28, 2016, at 1:53 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:

Hi Andy,

Everything is clear now, thank you!

On Tue, Jun 28, 2016 at 1:02 PM, Andrew Trick <atrick@apple.com> wrote:

Initializing via a typed pointer, in addition to changing the temporal memory state, also imposes a type on the allocated memory for the entire lifetime of the memory itself, from allocation to deallocation.

I see. Given that UnsafeMutablePoiner.initialize() has this very
important difference in semantics, did you consider reflecting it in
the name? Something like '.bindTypeAndInitialize()' -- but I'm sure a
better wording is possible.

Yes, I did consider that. I’m still open to it--maybe ‘.typedInitialize(with:). But...

(1) It’s awkward. The developer isn’t interested in binding the type at that point. It’s just a side effect of the way their unsafe pointer is being used.

(2) It would imply that the ‘.bindAndInitialize' entry point is the only way to bind the type of allocated memory. But once you have a typed pointer, it’s easy to initialize memory via a simple assignment:
ptrToA[0] = A() // where A is trivial
If ptrToA was in an uninitialized state, then that also binds the type.

It would be good to call this out in the proposal (I did not get this
part from the clarifications that you posted this morning.) So the
rule is that every typed store binds the type?

That's another way to obtain a typed pointer, but by itself it is well defined.

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

The following code 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())

It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.

I considered naming the cast `UnsafeRawPointer.bind<T>(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.

-Andy

···

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com> wrote:

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)

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)

That's another way to obtain a typed pointer, but by itself it is well defined.

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

And updated for the proposal's current syntax...

This is well-defined:

ptrA = rawPtr.initialize(A.self, with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(B.self, with: B())
···

On Jun 27, 2016, at 4:27 PM, Andrew Trick via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:

The following code 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())

It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.

I considered naming the cast `UnsafeRawPointer.bind<T>(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.

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)

That's another way to obtain a typed pointer, but by itself it is well defined.

Sorry, I meant to dereference that typed pointer as part of the expression. Now boom.

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

The following code 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())

It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.

How is that substantially different from my example?

···

Sent from my moss-covered three-handled family gradunza

On Jun 27, 2016, at 4:27 PM, Andrew Trick <atrick@apple.com> wrote:

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com> wrote:

I considered naming the cast `UnsafeRawPointer.bind<T>(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.

-Andy

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)

That's another way to obtain a typed pointer, but by itself it is well defined.

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

Doesn't that presume alignment?

···

Sent from my moss-covered three-handled family gradunza

On Jun 27, 2016, at 4:50 PM, Andrew Trick <atrick@apple.com> wrote:

On Jun 27, 2016, at 4:27 PM, Andrew Trick via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com> wrote:

And updated for the proposal's current syntax...

This is well-defined:

ptrA = rawPtr.initialize(A.self, with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(B.self, with: B())

The following code 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())

It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.

I considered naming the cast `UnsafeRawPointer.bind<T>(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.

Sent from my moss-covered three-handled family gradunza

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)

That's another way to obtain a typed pointer, but by itself it is well defined.

Sorry, I meant to dereference that typed pointer as part of the expression. Now boom.

Loading an UnsafePointer<T> from the contents of the raw pointer’s memory is fine if that’s what the memory contains. Dereferencing the loaded typed pointer is fine if that memory has been previously initialized with value of NonTrivialType.

Also, loading NonTrivialType directly from a raw pointer is fine if the memory contains an initialized NonTrivialType. This is fine:

  let v = rawPtr.load(NonTrivialType.self)

It returns an initialized `v` (a proper copy of the value in memory).

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

The following code 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())

It is hard to spot the difference between the two styles without drawing attention to the unsafe cast.

How is that substantially different from my example?

There are different sources of memory unsafety. One rule is that (roughly) when memory is dereferenced as a type it should contain an initialized value of that type (or related type). As long as users follow this very intuitive rule, and don’t force-cast into a typed pointer, then the raw pointer API is very safe!

Another source of memory unsafety is strict aliasing. This is not intuitive.

I am showing an example in which the memory location is never accessed using a type that is inconsistent with its initialized value. There is nothing wrong with the order and type of the initialization, access, deinitialization operations, so the user has followed the first, intuitive rule. The only thing wrong with my example is that the initialization uses a typed pointer. You can’t have two initializations of the same memory both using a typed pointer but with unrelated types.

All of this presumes that `A` and `B` are layout compatible (same alignment and size).

It’s true that the user could run into the same problem if they obtain a typed pointer via unsafeBitCast or rawPtr.load(UnsafePointer<T>). But we don’t want to provide an API explicitly for converting raw pointers into typed pointers without indicating that it opens up a new safety hole…

The *safe* way to get a typed pointer is this:
  let ptrA = rawPtr.initialize(A.self, with: A())

If you’re getting a typed pointer any other way then you need to be aware of the strict aliasing rules, which I suspect most users will not want to think about.

So, UnsafeRawPointer.cast(to: UnsafePointer<T>.Type) is *not* as safe as any other operation because it opens up a very subtle issue involving strict aliasing.

-Andy

···

On Jun 27, 2016, at 7:15 PM, Dave Abrahams <dabrahams@apple.com> wrote:
On Jun 27, 2016, at 4:27 PM, Andrew Trick <atrick@apple.com <mailto:atrick@apple.com>> wrote:

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:

I considered naming the cast `UnsafeRawPointer.bind<T>(to: T.Type)` to indicate that the allocated memory is being bound to a type for the entire duration of its allocation. But it's actually the call to `initialize` a typed pointer that binds the type.

-Andy

Sent from my moss-covered three-handled family gradunza

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)

That's another way to obtain a typed pointer, but by itself it is well defined.

Sorry, I meant to dereference that typed pointer as part of the expression. Now boom.

Loading an UnsafePointer<T> from the contents of the raw pointer’s
memory is fine if that’s what the memory contains. Dereferencing the
loaded typed pointer is fine if that memory has been previously
initialized with value of NonTrivialType.

Yes of course. The point was that rawPtr points to uninitialized
memory.

Also, loading NonTrivialType directly from a raw pointer is fine if
the memory contains an initialized NonTrivialType. This is fine:

  let v = rawPtr.load(NonTrivialType.self)

It returns an initialized `v` (a proper copy of the value in memory).

This is an important point, so I want to make sure I’m getting it across.

The following code is well-defined:

ptrA = rawPtr.initialize(with: A())
ptrA.deinitialize()
ptrB = rawPtr.initialize(with: B())

The following code 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())

It is hard to spot the difference between the two styles without
drawing attention to the unsafe cast.

How is that substantially different from my example?

There are different sources of memory unsafety. One rule is that
(roughly) when memory is dereferenced as a type it should contain an
initialized value of that type (or related type). As long as users
follow this very intuitive rule, and don’t force-cast into a typed
pointer, then the raw pointer API is very safe!

I still maintain that using cast to get an UnsafePointer that you'll
dereference is no less safe than using load to get an UnsafePointer that
you'll dereference.

Another source of memory unsafety is strict aliasing. This is not intuitive.

I am showing an example in which the memory location is never accessed
using a type that is inconsistent with its initialized value. There is
nothing wrong with the order and type of the initialization, access,
deinitialization operations, so the user has followed the first,
intuitive rule. The only thing wrong with my example is that the
initialization uses a typed pointer. You can’t have two
initializations of the same memory both using a typed pointer but with
unrelated types.

All of this presumes that `A` and `B` are layout compatible (same alignment and size).

It’s true that the user could run into the same problem if they obtain
a typed pointer via unsafeBitCast or
rawPtr.load(UnsafePointer<T>). But we don’t want to provide an API
explicitly for converting raw pointers into typed pointers without
indicating that it opens up a new safety hole…

The *safe* way to get a typed pointer is this:
  let ptrA = rawPtr.initialize(A.self, with: A())

If you’re getting a typed pointer any other way then you need to be
aware of the strict aliasing rules, which I suspect most users will
not want to think about.

So, UnsafeRawPointer.cast(to: UnsafePointer<T>.Type) is *not* as safe
as any other operation because it opens up a very subtle issue
involving strict aliasing.

IMO load is even worse, because there might not even be a valid pointer
of any kind in the address you're loading. I just don't see a
fundamental distinction here.

···

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

On Jun 27, 2016, at 7:15 PM, Dave Abrahams <dabrahams@apple.com> wrote:
On Jun 27, 2016, at 4:27 PM, Andrew Trick <atrick@apple.com <mailto:atrick@apple.com>> wrote:

On Jun 27, 2016, at 3:35 PM, Dave Abrahams <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:

--
Dave