> On Jan 27, 2017, at 7:36 PM, Zach Waldowski via swift-evolution > <[email protected]> wrote: > > 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.
I copied those parts of the documentation from Array. Unlike ArraySlice and ContiguousArray, due to NSArray compatibility, continuous storage for Array isn’t prepared until needed. I didn’t mean to imply that the relationship isn’t IS-A. Although now I don’t see any reason to ban ephemeral storage, the conforming type should act as if its element state is consistent between calls. (A conforming type that generates a new random block before each call, even ignoring previous mutations, isn’t very useful.) — Daryle Walker Mac, Internet, and Video Game Junkie darylew AT mac DOT com > Cheers! > Zachary Waldowski > [email protected] <mailto:[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 <https://github.com/CTMacUser> >> 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/>, Additional Commentary >> <https://lists.swift.org/pipermail/swift-evolution/> >> Bugs: SR-NNNN <https://bugs.swift.org/browse/SR-NNNN>, SR-MMMM >> <https://bugs.swift.org/browse/SR-MMMM> >> Previous Revision: 1 >> <https://github.com/apple/swift-evolution/blob/...commit-ID.../proposals/NNNN-filename.md> >> 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 >> <https://lists.swift.org/pipermail/swift-evolution/> >> 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] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
