Regards LM (From mobile)
> On Jun 28, 2016, at 12:25 AM, Dave Abrahams <[email protected]> wrote: > > >> on Mon Jun 27 2016, "L. Mihalkovic" <laurent.mihalkovic-AT-gmail.com> wrote: >> >> Regards >> (From mobile) >> >>> On Jun 27, 2016, at 8:39 AM, Dave Abrahams <[email protected]> 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 >>>>> <[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) >>> >>> 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). >>> 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 _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
