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