[swift-evolution] [swift-evolution-announce] [Review] SE-0107: UnsafeRawPointer API

Andrew Trick atrick at apple.com
Tue Jul 5 13:51:47 CDT 2016

> On Jul 2, 2016, at 10:10 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> I have a pile of naming quibbles; rather than describe them all in prose (which turned into a mess), I've annotated parts of the "Full UnsafeRawPointer API" section in a gist: <https://gist.github.com/brentdax/8f4ed4decafc1d18c4441092baa13cfe <https://gist.github.com/brentdax/8f4ed4decafc1d18c4441092baa13cfe>>.

I mostly agree with Brent's naming suggestions below. Anyone else want to weigh in?

> it's not clear that these operations are 
> nonmutating. I prefer `casting` because it's clearer about that.

Now we have:

  func bindMemory<T>(to: T.Type, capacity: Int) -> UnsafeMutablePointer<T>

  func assumingMemoryBound<T>(to: T.Type) -> UnsafeMutablePointer<T>

  func withMemoryRebound<T>(to: T.Type, capacity count: Int,
    _ body: @noescape (UnsafeMutablePointer<T>) throws -> ()) rethrows

"bind" is active. It has important side effects.
"assuming" is passive; it's just a "cast".
"withMemoryRebound" temporarily rebinds the type, but leaves it in its original state. "with" is sufficient to imply that the closure may mutate state.


  // In addition to the above point, I don't think "to" belongs in 
  // front of "contiguous" here. It makes sense with the verbs in 
  // `load` and `storeRaw` below, but not with this verb.
  // I also think `contiguous` basically implies `Index`, so we can 
  // just use `at`. Yes, I know about the `load` method with 
  // `atByteOffset`.
  // func initialize<T>(toContiguous: T.Type, atIndex: Int, with: T)
  //   -> UnsafeMutablePointer<T>
  func initialize<T>(contiguous: T.Type, at: Int, to: T)
    -> UnsafeMutablePointer<T>

This is a purely additive API that I'm personally in favor of dropping if it's confusing, but it was requested as a convenience...

The "toContiguous" was to avoid implying that a sequence of elements is being initialized, as opposed to a single element. "atIndex" was also suggested as a clarification. In hindsight I don't think either are likely to improve clarity in practice. I'm inclined to go with your suggestion, and if anyone thinks it's confusing we should drop the API for now:

  func initialize<T>(contiguous: T.Type, at: Int, to: T)
    -> UnsafeMutablePointer<T>


  // A little backwards, but `as` here is to support a more fluent 
  // `storeRaw` equivalent.
  // func load<T>(_: T.Type) -> T
  // func load<T>(_: T.Type, atByteOffset: Int) -> T
  func load<T>(as: T.Type) -> T
  func load<T>(fromByteOffset: Int, as: T.Type) -> T
  // func load<T>(fromContiguous: T.Type, atIndex: Int) -> T
  func load<T>(fromContiguous: T.Type, at: Int) -> T

  // I'm reversing the arguments here because the thing being stored is 
  // the obvious direct object of the verb "store".
  // func storeRaw<T>(_: T.Type, with: T)
  // func storeRaw<T>(toContiguous: T.Type, at: Int, with: T)
  func storeRaw<T>(_: T, as: T.Type)
  func storeRaw<T>(_: T, toContiguous: T.Type, at: Int)

I agree. Giving `load` and "as" label makes sense because the in-memory type may be different than the loaded type.

I strongly prefer your version of "storeRaw".

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

More information about the swift-evolution mailing list