[swift-evolution] Contiguous Memory and the Effect of Borrowing on Safety

John McCall rjmccall at apple.com
Mon Nov 7 18:22:32 CST 2016


> On Nov 7, 2016, at 3:55 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> on Mon Nov 07 2016, John McCall <swift-evolution at swift.org> wrote:
> 
>>> On Nov 6, 2016, at 1:20 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> 
>>> Given that we're headed for ABI (and thus stdlib API) stability, I've
>>> been giving lots of thought to the bottom layer of our collection
>> 
>>> abstraction and how it may limit our potential for efficiency.  In
>>> particular, I want to keep the door open for optimizations that work on
>>> contiguous memory regions.  Every cache-friendly data structure, even if
>>> it is not an array, contains contiguous memory regions over which
>>> operations can often be vectorized, that should define boundaries for
>>> parallelism, etc.  Throughout Cocoa you can find patterns designed to
>>> exploit this fact when possible (NSFastEnumeration).  Posix I/O bottoms
>>> out in readv/writev, and MPI datatypes essentially boil down to
>>> identifying the contiguous parts of data structures.  My point is that
>>> this is an important class of optimization, with numerous real-world
>>> examples.
>>> 
>>> If you think about what it means to build APIs for contiguous memory
>>> into abstractions like Sequence or Collection, at least without
>>> penalizing the lowest-level code, it means exposing UnsafeBufferPointers
>>> as a first-class part of the protocols, which is really
>>> unappealing... unless you consider that *borrowed* UnsafeBufferPointers
>>> can be made safe.  
>>> 
>>> [Well, it's slightly more complicated than that because
>>> UnsafeBufferPointer is designed to bypass bounds checking in release
>>> builds, and to ensure safety you'd need a BoundsCheckedBuffer—or
>>> something—that checks bounds unconditionally... but] the point remains
>>> that
>>> 
>>> A thing that is unsafe when it's arbitrarily copied can become safe if
>>> you ensure that it's only borrowed (in accordance with well-understood
>>> lifetime rules).
>> 
>> UnsafeBufferPointer today is a copyable type.  Having a borrowed value
>> doesn't prevent you from making your own copy, which could then escape
>> the scope that was guaranteeing safety.
>> 
>> This is fixable, of course, but it's a more significant change to the
>> type and how it would be used.
> 
> It sounds like you're saying that, to get static safety benefits from
> ownership, we'll need a whole parallel universe of safe move-only
> types. Seems a cryin' shame.

Well, if we can eliminate the unsafe, copyable types, that would be great, of course.
I don't know whether that's achievable given our C interop goals.

Another option is to attack escapes directly.  The safety guarantee you're looking
for is just that the value doesn't escape its scope, and while it's true that move-only
borrowed values aren't allowed to escape, that constraint doesn't *require* borrowing
or move-only-ness to work.  We already have non-escaping values in the language —
noescape functions — and there's nothing stopping us from applying that same logic
to other types.  There would be annotation problems, though, since existing functions
operating on pointers would be allowed to escape them.

John.


More information about the swift-evolution mailing list