[Proposal] Change (Dispatch)Data.withUnsafeBytes to use UnsafeMutableBufferPointer

Looking for feedback before submitting a PR: https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md

···

Change (Dispatch)Data.withUnsafeBytes to use UnsafeMutableBufferPointer

Proposal: SE-NNNN <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/NNNN-filename.md&gt;
Authors: Karl Wagner <https://github.com/karwa&gt;
Review Manager: TBD
Status: Awaiting review
During the review process, add the following fields as needed:

Decision Notes: Rationale <https://lists.swift.org/pipermail/swift-evolution/&gt;, Additional Commentary <https://lists.swift.org/pipermail/swift-evolution/&gt;
Bugs: SR-NNNN <Issues · apple/swift-issues · GitHub, SR-MMMM <Issues · apple/swift-issues · GitHub;
Previous Revision: 1 <https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md&gt;
Previous Proposal: SE-XXXX <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/XXXX-filename.md&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#introduction&gt;Introduction

The standard library's Array and ContiguousArray types expose the method withUnsafeBytes, which allows you to view their contents as a contiguous collection of bytes. The core libraries Foundation and Dispatch contain types which wrap some allocated data, but their withUnsafeBytes method only allows you to view the contents as a pointer to a contiguous memory location of a given type.

Swift-evolution thread: Discussion thread topic for that proposal <https://lists.swift.org/pipermail/swift-evolution/&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#motivation&gt;Motivation

The current situation makes it awkward to write generic code. Personally, I use the following extension in my projects to sort the naming confusion out:

protocol ContiguousByteCollection {
  func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
}

// stdlib types are fine.
extension Array: ContiguousByteCollection {}
extension ArraySlice: ContiguousByteCollection {}
extension ContiguousArray: ContiguousByteCollection {}

// corelibs types give us a pointer<T>, should be: { pointer<char>, count }
#if canImport(Dispatch)
  import Dispatch

  extension DispatchData : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif

#if canImport(Foundation)
  import Foundation

  extension Data : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif
Conceptually, the corelibs types are untyped regions of memory, and it would make sense for them to adopt the UnsafeRawBufferPointer model.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#proposed-solution&gt;Proposed solution

The proposed solution would be to deprecate the current methods on (Dispatch)Data (with 2 generic parameters), and replace them with methods with identical signatures to Array (with 1 generic parameter).

To be deprecated:

public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
Replaced with:

public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#source-compatibility&gt;Source compatibility

Source-breaking. Users binding a (Dispatch)Data to an UnsafePointer would instead have to call:

buffer.baseAddress!.assumingMemoryBound(to: T.self)
Which is a bit more to type, although maybe the deprecation of the old function could provide this replacement as a fix-it.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#effect-on-api-resilience&gt;Effect on API resilience

Source-breaking change to corelibs APIs.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#alternatives-considered&gt;Alternatives considered

A different method on Data and DispatchData, providing an UnsafeRawBufferPointer? There would still be a naming discrepency between the stdlib and corelibs types

+1, I have run into this awkwardness myself and wished the API were
different, exactly as you outline.

···

On Tue, Dec 27, 2016 at 03:16 Karl via swift-evolution < swift-evolution@swift.org> wrote:

Looking for feedback before submitting a PR:
https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md

Change (Dispatch)Data.withUnsafeBytes to use UnsafeMutableBufferPointer

   - Proposal: SE-NNNN
   <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/NNNN-filename.md&gt;
   - Authors: Karl Wagner <https://github.com/karwa&gt;
   - Review Manager: TBD
   - Status: Awaiting review

*During the review process, add the following fields as needed:*

   - Decision Notes: Rationale
   <https://lists.swift.org/pipermail/swift-evolution/&gt;, Additional
   Commentary <https://lists.swift.org/pipermail/swift-evolution/&gt;
   - Bugs: SR-NNNN <Issues · apple/swift-issues · GitHub, SR-MMMM
   <Issues · apple/swift-issues · GitHub;
   - Previous Revision: 1
   <https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md&gt;
   - Previous Proposal: SE-XXXX
   <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/XXXX-filename.md&gt;

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#introduction&gt;
Introduction

The standard library's Array and ContiguousArray types expose the method
withUnsafeBytes, which allows you to view their contents as a contiguous
collection of bytes. The core libraries Foundation and Dispatch contain
types which wrap some allocated data, but their withUnsafeBytes method
only allows you to view the contents as a pointer to a contiguous memory
location of a given type.

Swift-evolution thread: Discussion thread topic for that proposal
<https://lists.swift.org/pipermail/swift-evolution/&gt;

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#motivation&gt;
Motivation

The current situation makes it awkward to write generic code. Personally,
I use the following extension in my projects to sort the naming confusion
out:

protocol ContiguousByteCollection {
  func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
}
// stdlib types are fine.extension Array: ContiguousByteCollection {}extension ArraySlice: ContiguousByteCollection {}extension ContiguousArray: ContiguousByteCollection {}
// corelibs types give us a pointer<T>, should be: { pointer<char>, count }if canImport(Dispatch)
  import Dispatch

  extension DispatchData : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif

if canImport(Foundation)
  import Foundation

  extension Data : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif

Conceptually, the corelibs types *are* untyped regions of memory, and it
would make sense for them to adopt the UnsafeRawBufferPointer model.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#proposed-solution&gt;Proposed
solution

The proposed solution would be to deprecate the current methods on
(Dispatch)Data (with 2 generic parameters), and replace them with methods
with identical signatures to Array (with 1 generic parameter).

To be deprecated:

public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType

Replaced with:

public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#source-compatibility&gt;Source
compatibility

Source-breaking. Users binding a (Dispatch)Data to an UnsafePointer would
instead have to call:

buffer.baseAddress!.assumingMemoryBound(to: T.self)

Which is a bit more to type, although maybe the deprecation of the old
function could provide this replacement as a fix-it.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#effect-on-api-resilience&gt;Effect
on API resilience

Source-breaking change to corelibs APIs.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#alternatives-considered&gt;Alternatives
considered

   - A different method on Data and DispatchData, providing an
   UnsafeRawBufferPointer? There would still be a naming discrepency
   between the stdlib and corelibs types

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

+1

Always in favour of consistency/uniformity (even if source-breaking changes are needed)

Thanks Karl. Good observation.

I proposed exactly this API along with a few other UnsafeRawBufferPointer compatibility API’s during SE-0183. Look for Tony to follow up on this.

-Andy

···

On Dec 27, 2016, at 12:16 AM, Karl via swift-evolution <swift-evolution@swift.org> wrote:

Looking for feedback before submitting a PR: https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md

Change (Dispatch)Data.withUnsafeBytes to use UnsafeMutableBufferPointer

Proposal: SE-NNNN <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/NNNN-filename.md&gt;
Authors: Karl Wagner <https://github.com/karwa&gt;
Review Manager: TBD
Status: Awaiting review
During the review process, add the following fields as needed:

Decision Notes: Rationale <https://lists.swift.org/pipermail/swift-evolution/&gt;, Additional Commentary <https://lists.swift.org/pipermail/swift-evolution/&gt;
Bugs: SR-NNNN <Issues · apple/swift-issues · GitHub, SR-MMMM <Issues · apple/swift-issues · GitHub;
Previous Revision: 1 <https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md&gt;
Previous Proposal: SE-XXXX <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/XXXX-filename.md&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#introduction&gt;Introduction

The standard library's Array and ContiguousArray types expose the method withUnsafeBytes, which allows you to view their contents as a contiguous collection of bytes. The core libraries Foundation and Dispatch contain types which wrap some allocated data, but their withUnsafeBytes method only allows you to view the contents as a pointer to a contiguous memory location of a given type.

Swift-evolution thread: Discussion thread topic for that proposal <https://lists.swift.org/pipermail/swift-evolution/&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#motivation&gt;Motivation

The current situation makes it awkward to write generic code. Personally, I use the following extension in my projects to sort the naming confusion out:

protocol ContiguousByteCollection {
  func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
}

// stdlib types are fine.
extension Array: ContiguousByteCollection {}
extension ArraySlice: ContiguousByteCollection {}
extension ContiguousArray: ContiguousByteCollection {}

// corelibs types give us a pointer<T>, should be: { pointer<char>, count }
if canImport(Dispatch)
  import Dispatch

  extension DispatchData : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif

if canImport(Foundation)
  import Foundation

  extension Data : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif
Conceptually, the corelibs types are untyped regions of memory, and it would make sense for them to adopt the UnsafeRawBufferPointer model.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#proposed-solution&gt;Proposed solution

The proposed solution would be to deprecate the current methods on (Dispatch)Data (with 2 generic parameters), and replace them with methods with identical signatures to Array (with 1 generic parameter).

To be deprecated:

public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
Replaced with:

public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#source-compatibility&gt;

Hi Andy, everyone,

The short answer is that fixing struct Data requires a source breaking change (the enum for the deallocator has to change to use the raw buffer type), so I do not want to introduce it until Swift 4 provides a better transition path for this kind of change.

- Tony

···

On Jan 4, 2017, at 2:12 PM, Andrew Trick <atrick@apple.com> wrote:

On Dec 27, 2016, at 12:16 AM, Karl via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Looking for feedback before submitting a PR: https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md

Change (Dispatch)Data.withUnsafeBytes to use UnsafeMutableBufferPointer

Proposal: SE-NNNN <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/NNNN-filename.md&gt;
Authors: Karl Wagner <https://github.com/karwa&gt;
Review Manager: TBD
Status: Awaiting review
During the review process, add the following fields as needed:

Decision Notes: Rationale <https://lists.swift.org/pipermail/swift-evolution/&gt;, Additional Commentary <https://lists.swift.org/pipermail/swift-evolution/&gt;
Bugs: SR-NNNN <Issues · apple/swift-issues · GitHub, SR-MMMM <Issues · apple/swift-issues · GitHub;
Previous Revision: 1 <https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md&gt;
Previous Proposal: SE-XXXX <https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/XXXX-filename.md&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#introduction&gt;Introduction

The standard library's Array and ContiguousArray types expose the method withUnsafeBytes, which allows you to view their contents as a contiguous collection of bytes. The core libraries Foundation and Dispatch contain types which wrap some allocated data, but their withUnsafeBytes method only allows you to view the contents as a pointer to a contiguous memory location of a given type.

Swift-evolution thread: Discussion thread topic for that proposal <https://lists.swift.org/pipermail/swift-evolution/&gt;
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#motivation&gt;Motivation

The current situation makes it awkward to write generic code. Personally, I use the following extension in my projects to sort the naming confusion out:

protocol ContiguousByteCollection {
  func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T
}

// stdlib types are fine.
extension Array: ContiguousByteCollection {}
extension ArraySlice: ContiguousByteCollection {}
extension ContiguousArray: ContiguousByteCollection {}

// corelibs types give us a pointer<T>, should be: { pointer<char>, count }
if canImport(Dispatch)
  import Dispatch

  extension DispatchData : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif

if canImport(Foundation)
  import Foundation

  extension Data : ContiguousByteCollection {
    func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
      return try withUnsafeBytes { try body(UnsafeRawBufferPointer(start: $0, count: count)) }
    }
  }
#endif
Conceptually, the corelibs types are untyped regions of memory, and it would make sense for them to adopt the UnsafeRawBufferPointer model.

<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#proposed-solution&gt;Proposed solution

The proposed solution would be to deprecate the current methods on (Dispatch)Data (with 2 generic parameters), and replace them with methods with identical signatures to Array (with 1 generic parameter).

To be deprecated:

public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
Replaced with:

public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
<https://github.com/karwa/swift-evolution/blob/corelibs-unsafebytes/proposals/xxxx-corelibs-unsafebytes.md#source-compatibility&gt;

Thanks Karl. Good observation.

I proposed exactly this API along with a few other UnsafeRawBufferPointer compatibility API’s during SE-0183. Look for Tony to follow up on this.

-Andy