I like the sound of it so far, but my first major thought is that isn't it modeling a "has-a" relationship instead of an "is-a"? The buffer methods indicate that the data type *can* be represented as a buffer for the duration of the method call, but may not necessarily be before or after. Such a semantic distinction would also allow Data and DispatchData, as well as other theoretical data structures like a Deque (I think?) to participate.
Cheers! Zachary Waldowski [email protected] On Fri, Jan 27, 2017, at 06:40 PM, Daryle Walker via swift-evolution wrote: > I was perusing the library for array ideas, and noticed that several > types had methods in common, but without a grouping protocol. > Shouldn’t that be fixed? > > (Oh, if multiple protocols have an associated-type with the same name, > is that a problem? Is it a problem if they resolve differently for > each protocol attached to a given type? I’m asking because these > protocols reuse Sequence’s Element for their own purpose.) > > > Formal Protocol for Contiguous Storage Visitation > * Proposal: SE-NNNN > * Authors: Daryle Walker[1] > * Review Manager: TBD > * Status: *Awaiting review* > *During the review process, add the following fields as needed:* > * Decision Notes: Rationale[2], Additional Commentary[3] > * Bugs: SR-NNNN[4], SR-MMMM[5] > * Previous Revision: 1[6] > * Previous Proposal: SE-XXXX > Introduction > The standard library types Array, ArraySlice, and ContiguousArray have > an interface for visiting their elements as a contiguous block of > memory (arranging said elements to that configuration first if > necessary). These methods are all the same, but not under a common > protocol (i.e. seeming to match by "coincidence"). > This proposal seeks to correct that with two new protocols that these > types will implement. > Swift-evolution thread: Discussion thread topic for that proposal[7] > Motivation > Just adding these protocols for consistency is relatively minor, but > they may be used for other types. Particularly, they would be needed > if fixed-sized arrays are added to the language. > Proposed solution > The library array types will follow the > MutableContiguousBlockprotocol, which inherits from the > ContiguousBlock protocol. > extension Array: MutableContiguousBlock { } extension ArraySlice: > MutableContiguousBlock { } extension ContiguousArray: > MutableContiguousBlock { } > For example, a repackaging of the library's example code: > func change<T: MutableContiguousBlock>(object: inout T) -> T.Element > where T.Element: Integer { let sum = object.withUnsafeBufferPointer { > (buffer) -> T.Element in var result: T.Element = 0 for i in > stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) { result > += buffer[i] } return result } object.withUnsafeMutableBufferPointer { > buffer in for j in stride(from: buffer.startIndex, to: buffer.endIndex > - 1, by: 2) { swap(&buffer[j], &buffer[j + 1]) } } return sum } var > numbers = [1, 2, 3, 4, 5] print(change(object: &numbers)) // 9 > print(numbers) // [2, 1, 4, 3, 5] > Detailed design > /** Visitation protocol of the receiver's contiguous storage of > immutable elements. */ protocol ContiguousBlock { /// Inferred alias > to the element type to visit associatedtype Element /** Calls a > closure with a pointer to the receiver's contiguous storage. If no > such storage exists, it is first created. Often, the optimizer can > eliminate bounds checks within an array algorithm, but when that > fails, invoking the same algorithm on the buffer pointer passed into > your closure lets you trade safety for speed. The following example > shows how you can iterate over the contents of the buffer pointer: > let numbers = [1, 2, 3, 4, 5] let sum = > numbers.withUnsafeBufferPointer { buffer -> Int in var result = 0 for > i in stride(from: buffer.startIndex, to: buffer.endIndex, by: 2) { > result += buffer[i] } return result } // 'sum' == 9 - Parameter body: > A closure with an `UnsafeBufferPointer` parameter that points to the > contiguous storage for the receiver. If `body` has a return value, it > is used as the return value for this method. The pointer argument is > valid only for the duration of the closure's execution. - Returns: > The return value of the `body` closure parameter, if any. - SeeAlso: > Swift.UnsafeBufferPointer */ func withUnsafeBufferPointer<R>(_ body: > (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R } /** > Visitation protocol of the receiver's contiguous storage of elements, > allowing mutation. */ protocol MutableContiguousBlock: ContiguousBlock > { /** Calls the given closure with a pointer to the receiver's > mutable contiguous storage. If no such storage exists, it is first > created. Often, the optimizer can eliminate bounds checks within an > array algorithm, but when that fails, invoking the same algorithm on > the buffer pointer passed into your closure lets you trade safety for > speed. The following example shows modifying the contents of the > `UnsafeMutableBufferPointer` argument to `body` alters the contents of > the receiver: var numbers = [1, 2, 3, 4, 5] > numbers.withUnsafeMutableBufferPointer { buffer in for i in > stride(from: buffer.startIndex, to: buffer.endIndex - 1, by: 2) { > swap(&buffer[i], &buffer[i + 1]) } } print(numbers) // Prints "[2, 1, > 4, 3, 5]" - Warning: Do not rely on anything about `self` (the > receiver of this method) during the execution of the `body` closure: > It may not appear to have its correct value. Instead, use only the > `UnsafeMutableBufferPointer` argument to `body`. - Parameter body: A > closure with an `UnsafeMutableBufferPointer` parameter that points to > the contiguous storage for the receiver. If `body` has a return value, > it is used as the return value for this method. The pointer argument > is valid only for the duration of the closure's execution. - Returns: > The return value of the `body` closure parameter, if any. - SeeAlso: > withUnsafeBufferPointer, Swift.UnsafeMutableBufferPointer */ mutating > func withUnsafeMutableBufferPointer<R>(_ body: (inout > UnsafeMutableBufferPointer<Element>) throws -> R) rethrows -> R } > I don't know how the 3 library types implement this methods, but we > know it can be done. If added as an implicit interface to built-in fixed- > sized arrays, the implementers can use similar techniques or compiler > magic. I don't know the difficulty to adapt these interfaces with third- > party code. > Source compatibility > The changes are strictly additive, and at the library level, so there > should be no impact to existing code. > Effect on ABI stability > These changes should not affect ABI stability. > Effect on API resilience > As just stated, the addition of two protocol names to the API > shouldn't affect the ABI. > Alternatives considered > The main alternative is to do nothing. If fixed-sized arrays are later > added, they could have the same methods too, but there would still be > no common link. > Another alternative would make MutableContiguousBlock not inherit from > ContiguousBlock, meaning the former would need to define an Element > associated type. But don't see a need for a protocol with a read-write > method without its read-only counterpart available. > > > — > Daryle Walker > Mac, Internet, and Video Game Junkie > darylew AT mac DOT com > > _________________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution Links: 1. https://github.com/CTMacUser 2. https://lists.swift.org/pipermail/swift-evolution/ 3. https://lists.swift.org/pipermail/swift-evolution/ 4. https://bugs.swift.org/browse/SR-NNNN 5. https://bugs.swift.org/browse/SR-MMMM 6. https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md 7. https://lists.swift.org/pipermail/swift-evolution/
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
