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

Nate Cook natecook at gmail.com
Fri Dec 2 01:33:52 CST 2016

> On Nov 30, 2016, at 6:15 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> on Wed Nov 30 2016, Kevin Ballard <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> This sounds like a sensible idea. But there is one behavioral change you
>> haven't addressed, which is that this changes how indexes work on the
>> slice. With all other slice types that come to mind, the slice shares
>> the same indexes as the base, e.g.
>>  let ary = Array(0..<10)
>>  print(ary[3]) // prints 3
>>  print(ary[2..<5][3]) // still prints 3
> This is an important invariant that we need to maintain.
>> UnsafeBufferPointer is indexed using 0-based integers, so with your
>> proposal, slicing an UnsafeBufferPointer produces a value that uses
>> different indexes. We could solve this by adding a new field, but that
>> would break the expectation that startIndex is always zero. 
> I'm not sure that's an expectation we're obligated to honor.  Of course,
> once you get into “unsafe” territory like this, breaking even the
> expectations that aren't based on documented guarantees can be really
> dangerous.
> We probably ought to have wrapped those integers in some Index type
> specific to UnsafeBufferPointer, so zero wasn't even a value.
>> But we can't just ignore this problem, because algorithms that are
>> designed around collections may assume that slices preserve indexes.
>> In addition, since you point out that UnsafeRawBufferPointer is already
>> its own subsequence, and that type also guarantees that startIndex is
>> always zero, it sounds like we already have an instance of this problem
>> in the stdlib, and so this needs to be addressed with
>> UnsafeRawBufferPointer as well.
> Sounds like it!

Argh, thanks to Kevin for pointing all this out!

I can see at least three approaches to resolving the inconsistency between the two sets of buffer types and correcting index sharing for raw buffer pointers.

1) Switch to using Slice as a wrapper for UnsafeRawBufferPointer.
2) Make all buffer pointers their own slices, keeping integer-based indices, but remove the zero-based index expectation. With this we'd need to add an additional stored property to keep track of the relative offset from the "original" buffer.
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.

The first option would certainly be the smallest change; the third seems like it would do the most good, for the reasons Dave laid out. I've tried the third option out here for raw buffers:


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161202/75242b9e/attachment.html>

More information about the swift-evolution mailing list