> 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

Reply via email to