<div dir="ltr"><div><div>On Wed, Jul 12, 2017 at 12:23 AM, Dave Abrahams via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br></div></div><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span class="gmail-">/../<br>
</span>As ever, my first question when a new protocol is proposed is, “what<br>
generic algorithms rely on this protocol?”<br><span class="gmail-HOEnZb"><font color="#888888"><br></font></span></blockquote><div><br></div><div><div>First, please note that I made some mistakes in the code earlier in this conversation as I did not have a compiler at hand, a better version can be found in the PS-section of this post: <a href="https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170710/005921.html">https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20170710/005921.html</a></div></div><div><br></div><div>It contains some more context also.</div><div><br></div><div>To answer your question: I&#39;m using it as one of the basic building blocks needed for implementing generic statically allocated Vector types with type-level Element and Count/Index (despite the current limitations of Swift&#39;s type system!) , more specifically:</div><div>...</div><div><div>protocol Vector {</div><div>    associatedtype Index: VectorIndex</div><div>    associatedtype Element</div><div>    init(elementForIndex: (Index) -&gt; Element)</div><div>    subscript(index: Index) -&gt; Element { get set }</div><div>}</div></div><div>...</div><div><div>protocol VectorIndex where</div><div>    VectorUInt32.Element == UInt32, VectorUInt32.Index == Self, // I guess this should not work</div><div>    VectorUInt64.Element == UInt64, VectorUInt64.Index == Self  // but it&#39;s actually a workaround …</div><div>{</div><div>    associatedtype VectorUInt32 : Vector // … for some bug that makes it necessary to add</div><div>    associatedtype VectorUInt64 : Vector // the constraints up there instead of down here ...</div><div>    ...</div><div>}</div></div><div>...</div><div>enum Index1 : VectorIndex { // Yes, there are situations when we want a 1-element vector.<br></div><div><div>    typealias VectorUInt8 = Vector1&lt;UInt8&gt;</div><div>    typealias VectorUInt16 = Vector1&lt;UInt16&gt;</div><div>    typealias VectorUInt32 = Vector1&lt;UInt32&gt;</div><div>    typealias VectorUInt64 = Vector1&lt;UInt64&gt;</div><div>    case i0</div><div>}</div><div>enum Index2 : VectorIndex {<br></div></div><div><div>    typealias VectorUInt8 = Vector2&lt;UInt8&gt;</div><div>    typealias VectorUInt16 = Vector2&lt;UInt16&gt;</div><div>    typealias VectorUInt32 = Vector2&lt;UInt32&gt;</div><div>    typealias VectorUInt64 = Vector2&lt;UInt64&gt;</div><div>    case i0, i1</div><div>}</div><div>enum Index3 : VectorIndex {</div><div>    typealias VectorUInt8 = Vector3&lt;UInt8&gt;</div><div>    typealias VectorUInt16 = Vector3&lt;UInt16&gt;</div><div>    typealias VectorUInt32 = Vector3&lt;UInt32&gt;</div><div>    typealias VectorUInt64 = Vector3&lt;UInt64&gt;</div><div>    case i0, i1, i2</div><div>}</div></div><div><div>enum Index4 : VectorIndex {</div><div>    typealias VectorUInt8 = Vector4&lt;UInt8&gt;</div><div>    typealias VectorUInt16 = Vector4&lt;UInt16&gt;</div><div>    typealias VectorUInt32 = Vector4&lt;UInt32&gt;</div><div>    typealias VectorUInt64 = Vector4&lt;UInt64&gt;</div><div>    case i0, i1, i2. i3</div><div>}</div></div><div>// Add more if needed, I haven&#39;t yet needed more than 4.</div><div>...<br></div><div>...</div><div>// I leave Vector1, Vector3 and Vector4 out since they are obvious given this:</div><div><div>struct Vector2&lt;E&gt; : Vector {</div><div>    typealias Index = Index2</div><div>    typealias Element = E</div><div>    var elements: (Element, Element)</div><div>    init(elementForIndex: (Index) -&gt; Element) {</div><div>        elements = (elementForIndex(.i0), elementForIndex(.i1))</div><div>    }</div><div>    subscript(index: Index) -&gt; Element {</div><div>        get {</div><div>            switch index {</div><div>            case .i0: return elements.0</div><div>            case .i1: return elements.1</div><div>            }</div><div>        }</div><div>        set {</div><div>            switch index {</div><div>            case .i0: elements.0 = newValue</div><div>            case .i1: elements.1 = newValue</div><div>            }</div><div>        }</div><div>    }</div><div>}</div></div><div>...</div><div>// This type of Vector is needed for the interesting and hard version of map in the example below:</div><div><div>struct PrimaryBitPatternBasedVector&lt;Base, E&gt; : Vector where</div><div>    Base: Vector,</div><div>    E: PrimaryBitPatternRepresentable,</div><div>    E.PrimaryBitPattern == Base.Element</div><div>{</div><div>    typealias Index = Base.Index</div><div>    typealias Element = E</div><div>    var base: Base</div><div>    init(elementForIndex: (Index) -&gt; Element) {</div><div>        base = Base.init { elementForIndex($0).bitPattern }</div><div>    }</div><div>    subscript(index: Index) -&gt; Element {</div><div>        get { return Element(bitPattern: base[index]) }</div><div>        set { base[index] = newValue.bitPattern }</div><div>    }</div><div>}</div></div><div><div>...</div><div><div>extension Vector {</div><div>    ...</div><div>    // It&#39;s easy as long as the return type is just Self.</div><div>    func map(transform: (Element) -&gt; Element) -&gt; Self {</div><div>        return .init { transform(self[$0]) }</div><div>    }</div><div>    // But THIS MAP is an interesting example of something that is very hard/impossible to accomplish given Swift&#39;s current type system, so we need to special case it in some way, and one way that includes most of the interesting element types is to do this, which will cover any type whose values can be represented as a fixed width bit pattern:</div><div>    func map&lt;ResultingElement&gt;(transform: (Element) -&gt; ResultingElement) -&gt; PrimaryBitPatternBasedVector&lt;Index.VectorUInt8, ResultingElement&gt; {<br></div><div>        return .init { transform(self[$0]) }</div><div>    }</div><div>    func map&lt;ResultingElement&gt;(transform: (Element) -&gt; ResultingElement) -&gt; PrimaryBitPatternBasedVector&lt;Index.VectorUInt16, ResultingElement&gt; {</div><div>        return .init { transform(self[$0]) }</div><div>    }</div><div>    func map&lt;ResultingElement&gt;(transform: (Element) -&gt; ResultingElement) -&gt; PrimaryBitPatternBasedVector&lt;Index.VectorUInt32, ResultingElement&gt; {</div><div>        return .init { transform(self[$0]) }</div><div>    }</div><div>    func map&lt;ResultingElement&gt;(transform: (Element) -&gt; ResultingElement) -&gt; PrimaryBitPatternBasedVector&lt;Index.VectorUInt64, ResultingElement&gt; {</div><div>        return .init { transform(self[$0]) }</div><div>    }</div><div>    ...</div><div>}<br></div></div></div><div>...</div><div><br></div><div>Phew,</div><div>Don&#39;t know if that makes any sense when stripped down and edited like that but I don&#39;t feel like posting the entire code because it needs better naming, cleaning up, etc. first.</div><div><br></div><div>But more generally I think that this little protocol (PrimaryBitPatternRepresentable (but better named)) would just tie together / systemize functionality that is already in the standard library, similarly to how the Numeric protocol tied together things that were (almost) already in the std lib, although this is of course much more trivial and at a much lower level (bits/storage instead of numeric computation).</div><div><br></div><div>I&#39;m totally fine with just using my own implementation though and I&#39;m just putting it here as a naive suggestion to see if perhaps anyone else would find it useful. Perhaps my attempts at naming it (BitPatternRepresentable, PrimaryBitPatternRepresentable) is confusing things a little, but the idea is just:</div><div>Every type whose values can be represented by a fixed number of bits (8, 16, 32 or 64) is &quot;PrimaryBitPatternRepresentable&quot; and has an associated type &quot;PrimaryBitPattern&quot; that is one of the four &quot;PrimaryBitPatternProtocol&quot;-conforming types: UInt8, UInt16, UInt32 or UInt64.</div><div><br></div><div>/Jens</div><div><br></div><div><br></div></div></div></div>