[swift-evolution] [swift-evolution-announce] [Review] SE-0127: Cleaning up stdlib Pointer and Buffer Routines

Dave Abrahams dabrahams at apple.com
Fri Jul 22 20:35:23 CDT 2016


on Fri Jul 22 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote:

> On Fri, Jul 22, 2016 at 6:49 PM, Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>>
>> on Fri Jul 22 2016, Xiaodi Wu <swift-evolution at swift.org> wrote:
>>
>> > On Fri, Jul 22, 2016 at 5:06 PM, Dave Abrahams via swift-evolution <
>> > swift-evolution at swift.org> wrote:
>> >
>> >>
>> >> on Fri Jul 22 2016, Bob Wilson <swift-evolution at swift.org> wrote:
>> >>
>> >> > It is not so clear what to do about SR-1956. (Charlie and I had some
>> >> > comments on this in https://github.com/apple/swift-evolution/pull/437
>> >> > <https://github.com/apple/swift-evolution/pull/437>.) Jordan raised
>> >> > the objection that when using withUnsafePointer with a global, there
>> >> > is an expectation that you’ll get the same address every
>> >> > time. Removing inout would cause the argument to be passed by value
>> >> > and the address would refer to a copy. Dmitri agreed that this could
>> >> > be a problem. On the other hand, if you don’t care about the address,
>> >> > or if you’re not using a value type, it would indeed be convenient to
>> >> > have a version of withUnsafePointer that does not require an inout
>> >> > argument.
>> >> >
>> >> > Option 1: Keep inout (not addressing SR-1956). In this case, there’s
>> >> > no reason to have both withUnsafePointer and
>> >> > withUnsafeMutablePointer. If you want to call a function that expects
>> >> > an UnsafePointer, you can give it an UnsafeMutablePointer and there
>> >> > will be an implicit conversion to make it work. I discussed this with
>> >> > Apple’s stdlib team and they recommended that if we have only one
>> >> > function we use the shorter name “withUnsafePointer” and have it use
>> >> > an UnsafeMutablePointer.
>> >>
>> >> Very much in favor of Option 1.
>> >>
>> >
>> > Ditto, except that I think there is some value in keeping both (i.e.
>> doing
>> > nothing): allowing the user to document intent. It would be inconsistent
>> > and potentially confusing to call the function that returns an
>> > `UnsafeMutablePointer` `withUnsafePointer`.
>>
>> It doesn't return an `UnsafeMutablePointer`, it passes an
>> `UnsafeMutablePointer` to the body of the closure.
>>
>
> Brainfart. Yes, that's what I meant to write. Sorry.
>
>> > It's rarely used enough, and the shorter name needlessly raises the
>> > question of where I'm really "supposed to be" mutating the
>> > pointee.
>>
>> I don't understand; you only have the pointee inside the closure.
>> That's where you mutate it (obviously?)
>>
>
> If my closure does not mutate the pointee, `withUnsafePointer(_:)` allows
> me to document that. Everything *works* with
> `withUnsafeMutablePointer(_:)`, but I cannot read the code and understand
> that no mutation has happened within the body of the closure. [Am I wrong
> on this?]

No, you're right.

> For instance, I've been working with some of the Accelerate.framework
> functions and the arguments are often cryptic. Take this call:
>
> ```
> cblas_sgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, m, n, k, 1, matrix,
> m, b, k, 1, &c, m)
> ```
>
> There are times when I'd want to
> call `cblas_sgemm(_:_:_:_:_:_:_:_:_:_:_:_:_:_:)` inside an
> `withUnsafe[Mutable]Pointer(_:)` closure. Distinguishing
> `withUnsafePointer(_:)` and `withUnsafeMutablePointer(_:)` would allow a
> reader to know from the outset if `$0.pointee is mutated without having to
> know that the second-from-last argument is the one that stores the result
> (it is not consistently second-from-last; for vDSP_* functions, it's often
> the third-from-last argument, and for others it can be the first argument).
> Removing the current `withUnsafePointer(_:)` would decrease clarity for the
> reader here.

Okay, fair enough.

>> I've not had to use these functions much, but the distinction between
>> > `Array.withUnsafeBufferPointer(_:)` and
>> > `Array.withUnsafeMutableBufferPointer(_:)` has conditioned me to
>> > mutate the pointee using only "mutable" functions.
>>
>> Not sure if you're just drawing an analogy,
>
> I was trying to. I guess ineffectively.
>
>> but if not, those two
>> methods are not under discussion here.  They are meaningfully different,
>> whereas the existing functions are not, and the one currently called
>> withUnsafePointer is always going to cause people to complain about
>> having to pass a mutable variable.
>>
>> As a fallback position, I would suggest we only provide the mutating
>> one, but with its existing name.  But I still prefer the shorter name.
>>
>> >
>> >> >
>> >> > Option 2: Fix SR-1956 and have two functions, one with inout and the
>> >> > other not. This would address the inconvenience of not being able to
>> >> > use withUnsafePointer with immutable values, while still supporting
>> >> > the existing behavior. The question then would be what to call these
>> >> > two functions.
>> >>
>> >> We do not need to support new use-cases in this release, and this would
>> >> be unsatisfying because the “address of a global” property that Jordan
>> >> argued for would not hold for the immutable version.
>> >>
>> >> > - Option 2a. Combine the two existing functions as in Option 1 and use
>> >> > a new name for the non-inout version, e.g.,
>> >> > withUnsafePointer(toCopyOf:), so that it won’t be confused with the
>> >> > old function. (That particular name doesn’t work very well when
>> >> > dealing with references to objects, since the object itself would not
>> >> > be copied. I haven’t yet come up with a better name, though.) One
>> >> > advantage of this approach is that we would not need to rush the new
>> >> > function into Swift 3 since it would be an additive change.
>> >>
>> >> Not rushing that into Swift 3 is the same as Option 1.
>> >>
>> >> > - Option 2b. Switch to use withUnsafeMutablePointer for all the cases
>> >> > where you care about the getting the same address. Change
>> >> > withUnsafePointer to be the non-inout version. Charlie suggested that
>> >> > we could have the migrator convert all existing uses on
>> >> > withUnsafePointer in Swift 2 code to use withUnsafeMutablePointer in
>> >> > Swift 3, but I’m not sure how well that would work.
>> >>
>> >> That's exactly the same outcome, with respect to the language/library
>> >> surface, as Option 2 AFAICT.  Can we simplify this list of options?
>> >>
>> >> --
>> >> Dave
>> >>
>> >> _______________________________________________
>> >> swift-evolution mailing list
>> >> swift-evolution at swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>> >>
>> > _______________________________________________
>> > swift-evolution mailing list
>> > swift-evolution at swift.org
>> > https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>>
>> --
>> Dave
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>

-- 
Dave


More information about the swift-evolution mailing list