[swift-evolution] SE-0138 UnsafeBytes

Andrew Trick atrick at apple.com
Wed Sep 7 01:29:04 CDT 2016


> On Sep 2, 2016, at 5:14 PM, Andrew Trick via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> 
>> On Sep 2, 2016, at 11:14 AM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> 
>> on Thu Sep 01 2016, Andrew Trick <swift-evolution at swift.org> wrote:
>> 
>>> I’m resending this for Review Manager Dave A. because the announce list is dropping his messages...
>>> 
>>> Hello Swift community,
>>> 
>>> The review of "UnsafeBytes" begins now and runs through September
>>> 7th. This late addition to Swift 3 is a follow-up to SE-0107:
>>> UnsafeRawPointer. It addresses common use cases for UnsafeRawPointer,
>>> allowing developers to continue working with collections of UInt8 values,
>>> but now doing so via a type safe API. The UnsafeBytes API will not require 
>>> direct manipulation of raw pointers or reasoning about binding memory.
>>> 
>>> The proposal is available here:
>>> 
>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0138-unsafebytes.md <https://github.com/apple/swift-evolution/blob/master/proposals/0138-unsafebytes.md>>
>>> 
>>> * What is your evaluation of the proposal?
>> 
>> I strongly support inclusion of the feature, but I have issues with the
> 
> Clearly, otherwise you wouldn't have announced it 4 times ;)
> 
>> name.  It seems to me that in order to fit into the standard library, it
>> should be called Unsafe[Mutable]RawBufferPointer.  Each part of the name
> 
> Well, that's natural from a stdlib designer's viewpoint. It is almost
> identical functionality, but it also exposes the UnsafeRawPointer API
> for loading and storing arbitrary types. This naming issue was
> discussed for a couple weeks on swift-evolution. Let's see if I can
> recap inline with your comments.
> 
>> conveys something important, and for the same reasons we're using
>> Unsafe[Mutable]BufferPointer instead of UnsafeMutableElements, we should
>> stick to the scheme:
>> 
>> - “Unsafe,” because you can break memory safety with this tool
> 
> OK. Let's not drop that one!
> 
>> - “Raw,” because the fundamental model is that of “raw,” rather than
>> “typed,” memory.
> 
> To me, bytes only exist in memory. Accessing a byte, as opposed to some
> in-memory type, is always a raw access.
> 
>> - “Buffer,” because it works on a series of contiguous elements of known
>> length.
> 
> To me, bytes always represent a contiguous chunk of raw memory. The
> term implies that we're dealing with memory layout, as opposed to just
> some opaque chunk of data, which is I think what Foundation Data is for.
> 
>> - “Pointer,” because it has reference semantics!  When you pass one of
>> these things around by value, you're not passing the bytes; you're
>> passing a shared reference to the bytes.
> 
> Unsafe means that this value doesn't own the memory. I agree with you
> that reference semantics are important, and we need to clearly
> distinguished this from something like Data. I just think Unsafe is
> enough for the name.
> 
> UnsafeMutableRawBufferPointer does not actually convey that it can be
> viewed as a collection of 8-bit values, which is fairly important.
> 
> Now that I've satisfied my pedantic side, let's look at it from the developer's side.
> To me it's a question of whether a longer or shorter name is more meaningful in
> the natural setting of users' source code:
> 
> func foo(bytes: UnsafeMutableRawBufferPointer)
> 
> withUnsafeMutableRawBufferPointer(to: &header) {
>  foo(bytes: $0)
> }
> ---
> func foo(bytes: UnsafeMutableBytes)
> 
> withUnsafeBytes(of: &header) {
>  write(bytes: $0)
> }
> 
> I don't think the longer name is more descriptive. I do think the
> shorter name is more intuitive and meaningful.
> 
> UnsafeMutableRawPointer is already too long to be recognizable to
> users. A benefit of UnsafeBytes is that the most developers won't need
> to know how to work directly with raw pointers. So the name doesn’t
> need to evoke them.
> 
> -Andy

Update on the naming debate...

I've tentatively updated this proposal renaming UnsafeBytes to UnsafeRawBufferPointer. It's not bad as long as the `withUnsafeBytes` name remains:

https://github.com/atrick/swift-evolution/blob/unsafebytes/proposals/0138-unsaferawbufferpointer.md

I've heard a few compelling arguments to use a long type name. I'm the only person who's argued in favor of the short name. Here are the key points that have convinced me to give in:

- Although I would like "bytes" to only refer to raw, untyped memory,
  in reality it means different things to different people.

- We do not want to promote using this type in public API, except as
  an alternative to other UnsafePointer related types. APIs should
  really migrate to safe, managed types.

- In practice, we may end up with overloads that the more descriptive
  type can help clarify. For example, Data.withUnsafeBytes already
  passes an UnsafePointer to its closure. That API already shipped, but
  we may want a "raw" variant of it. Having the closure take
  `UnsafeRawBufferPointer` clarifies the distinction.

- What was more important to me was that the closure-taking functions
  are reasonably named and imply a collection of bytes over some
  value, which is not necessarilly a buffer to begin with. We can
  still do that. The function name can indicate a collection of bytes
  over some value's representation, while the argument type (which
  doesn't need to be spelled out) specifies that the collection is
  represented as a raw pointer with length:
  `withUnsafeBytes(of: &value) { p: UnsafeRawBufferPointer in ...}

Does anyone have a good argument to keep the short UnsafeBytes type name?

-Andy

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


More information about the swift-evolution mailing list