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

Dave Abrahams dabrahams at apple.com
Sun Jul 24 12:33:46 CDT 2016


on Sun Jul 24 2016, Charlie Monroe <charlie-AT-charliemonroe.net> wrote:

>>> Ok, I'll update the proposal to withdraw the change of inout for
>>> withUnsafePointer.
>> 
>> We could also add
>> 
>>    withUnsafePointer(toCopyOf: x)
>> 
>> but that can also come later if we decide we need it.
>
> I don't think this is correct naming. It might be in case of structs,
> but in case of a pointer on the heap, I think this is misleading. It
> would be absolutely valid to write:
>
> let obj = NSObject()
> withUnsafePointer(toCopyOf: obj) { ptr in
> 	print(ptr)
> }
>
> and it doesn't create any copy of anything. 

No, it actually does create a copy of the argument.  When you copy a
reference, that's a real thing, even though it doesn't copy the instance
the reference refers to.

> I'd personally prefer renaming the current behavior to
> withUnsafePointer(byReferenceTo:) which is more descriptive.

I don't see how that helps anything.

>> Under the discussion for the pull request, Bob mentioned possible
>>> removal of the multi-pointer variants
>>> (i.e. withUnsafe[Mutable]Pointers) - is this something that you'd
>>> agree on?
>> 
>> Absolutely.
>
> I've updated the proposal and created a pull request.
>
>> 
>>> If so, I'd add this to the proposal since I agree that this is an API
>>> that is rarely used, can be used by nesting two
>>> withUnsafe[Mutable]Pointer calls and is limited to three pointers at
>>> max anyway. It almost feels like NSAssert1, NSAssert2, etc.
>>> 
>>>> On Jul 23, 2016, at 3:35 AM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 
>>>> 
>>>> 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
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list