[swift-evolution] [Pitch] Normalize Slice Types for Unsafe Buffers

Dave Abrahams dabrahams at apple.com
Thu Dec 8 16:11:01 CST 2016

on Thu Dec 08 2016, Alexis Beingessner <swift-evolution at swift.org> wrote:

>> On Dec 8, 2016, at 3:50 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> on Thu Dec 08 2016, Ben Cohen <ben_cohen-AT-apple.com> wrote:
>>>> On Dec 2, 2016, at 8:27 PM, Nate Cook <natecook at gmail.com> wrote:
>>>>> On Dec 2, 2016, at 2:12 PM, Ben Cohen via swift-evolution
>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>>> wrote:
>>>>>> On Dec 1, 2016, at 11:33 PM, Nate Cook via swift-evolution
>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>
>>>>>> wrote:
>>>>>> 3) Make all buffer pointers their own slices but use a different
>>>>>> index type. If the indices were just wrapped pointers, that would
>>>>>> handle the index sharing without needing an additional property on
>>>>>> the buffer. We could also maintain integer-based stridable
>>>>>> conformance (which greatly simplifies index arithmetic), since the
>>>>>> indices would just offset by a byte for raw buffers or a stride
>>>>>> for typed buffers.
>>>>> Unfortunately, switching to non-integer indices would change this
>>>>> from being mildly source-breaking to being extremely
>>>>> source-breaking, as there’s lots of code out there using buffers
>>>>> today indexing them with integers (including integer literals).
>>>>> The big win with UnsafeBufferPointer having an integer index is
>>>>> it’s a drop-in replacement for arrays, so when you hit a
>>>>> performance problem using an array you can quickly switch to using
>>>>> a buffer under most circumstances instead without having to change
>>>>> much of your code – including code that uses for i in
>>>>> 0..<myArray.count, of which there is a lot out there in the
>>>>> wild. Switching to an opaque index would break anyone doing that.
>>>> It is definitely very source-breaking, though with relatively simple fixits:
>>>>    buf[0] ---> buf[buf.startIndex]
>>>>    buf[3] ---> buf[buf.startIndex + 3]
>>>>    buf[i] ---> buf[buf.startIndex + i]
>>>> Any integer arithmetic happening outside the subscript could be left
>>>> unchanged. If that cost isn't worth the benefit, then making
>>>> UnsafeRawBufferPointer use Slice as its slice type is probably the
>>>> best way to resolve that issue.
>>>> Nate
>>> The fixits aren’t quite that simple for slices, though:
>>>    let slice = buf[3..<6]
>>>    slice[3] —> slice[slice.startIndex + 0] // fixit would somehow need to know this is 0 not 3
>>>    slice[i] —> slice[slice.startIndex + ??] // or even need to
>>> know this is, erm, I haven’t had enough coffee this morning
>>> The other downside is it would thwart speculatively switching an Array
>>> to an UnsafeBuffer to see if that was a bottleneck, then switching
>>> back.
>>>> On Dec 1, 2016, at 11:33 PM, Nate Cook via swift-evolution <swift-evolution at swift.org> wrote:
>>>> 1) Switch to using Slice as a wrapper for UnsafeRawBufferPointer.
>>> Based on the above, it seems like this is the least bad option, and we
>>> need to do this ASAP as currently UnsafeRawBufferPointer is
>>> non-compliant with the requirements of slicing and needs changing
>>> before it’s more widely adopted.
>> Or we could say that UnsafeRawBufferPointer isn't a Collection.  Making
>> it a Collection in the first place has always seemed suspect to me.
> If this is considered a viable option, it's the one I want. Passing
> types without bounds checks into generic "safe" code shouldn't be this
> easy. 

I don't think I agree, but that's a separate argument, about
UnsafeBufferPointer.  This is about passing *untyped* memory without
bounds checks.

> You should need to explicitly wrap it up in something safe. And I
> really don't want the known-to-be-error-prone indexing model in
> concrete unsafe code.


More information about the swift-evolution mailing list