<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I’ll keep this quick since I see upthread you have already revised the proposal.</div><br class=""><div><blockquote type="cite" class=""><div class="">On May 29, 2016, at 12:36 PM, Austin Zheng &lt;<a href="mailto:austinzheng@gmail.com" class="">austinzheng@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">…something like the above is definitely a "nice to have", but not having it will close off certain use cases.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Oh, this is interesting. So a way to specify an equality relationship between "adjacent" sets of associated types?</div></div></div></blockquote><div><br class=""></div><div>Right, that was what I had in mind, and I can think of uses for such neighbor-to-neighbor type relationships.</div><div><br class=""></div><div>There may be uses for other relationships—both beyond equality and beyond neighbor-to-neighbor—but I can’t think of any offhand.</div><div><br class=""></div><div>One other pack-level constraint came to mind:</div><div><br class=""></div><div>- can you enforce (T…) is *exactly* (T,T,T,…) N times? (e.g. T0 == T1, etc., not just "conforms to same protocols” or “have identical associated types”)</div><div><br class=""></div><div>…along with some “pack-to-pack” constraints:</div><div><br class=""></div><div>- if you have e.g. 2+ packs, can you enforce (T…) and (U…) have the same arity?</div><div>- if you have e.g. 2+ packs, could you enforce e.g. T.Foo… == U.Bar ?</div><div><br class=""></div><div>…as always nice-to-have, but throwing them out there for consideration.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">I'll write something up.</div><div class=""><br class=""></div><div class=""><div class="">for index in 0..&lt;#count(T…) {</div><div class="">&nbsp; &nbsp; if let v = tables[index][key] {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; valueCache[key] = v</div><div class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="Apple-tab-span" style="white-space: pre;">        </span>return v</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">I assume this is all compile time code generation (unroll the loop in the source #count(T...) times for each arity that T... is instantiated as, with a different 'tables' pack member value for each unrolled loop iteration).&nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>I’d assume so too, but thinking it through I think it needs some alternative way of being expressed.</div><div><br class=""></div><div>If you look @ the “obvious” implementation for the above as written, it unrolls into something like this:</div><div><br class=""></div><div>&nbsp; if let v = tables[0][key] { … } // assume returns out of here on success</div><div>&nbsp; if let v = tables[1][key] { … } // assume returns out of here on success</div><div>&nbsp; //…etc...</div><div><br class=""></div><div>…but b/c tuples aren’t directly subscriptable, those `tables[index][key]` expressions themselves would perhaps get expanded into the equivalent of, e.g.:</div><div>&nbsp;</div><div>&nbsp; private func __subscriptTables(index index: Int, key: K) -&gt; V? {</div><div>&nbsp; &nbsp; switch index {</div><div>&nbsp; &nbsp; &nbsp; &nbsp;case 0: return tables.0[key]</div><div>&nbsp; &nbsp; &nbsp; &nbsp;case 1: return tables.1[key]</div><div>&nbsp; &nbsp; &nbsp; &nbsp;// etc...</div><div>&nbsp; &nbsp; &nbsp; &nbsp;default: fatalError(“Invalid subscript into variadic…blah blah”)</div><div>&nbsp; &nbsp; }</div><div>&nbsp; }</div><div><br class=""></div><div>…and so the original expansion would be more like:</div><div><br class=""></div><div><div>&nbsp; if let v =&nbsp;__subscriptTables(index:0, key: key) { … } // assume returns out of here on success</div><div>&nbsp; if let v =&nbsp;__subscriptTables(index:1, key: key) { … } // assume returns out of here on success</div><div>&nbsp; //…etc...</div><div class=""><br class=""></div><div class="">….which repeats the switch at each line. In theory the optimizer can know to inline `__subscriptTables`,&nbsp;notice `index` is known at compile-time, replace the switch with direct access, and arrive at the code you “really want”:</div><div class=""><br class=""></div><div class=""><div>&nbsp; if let v = tables.0[key] { … } // assume returns out of here on success</div><div>&nbsp; if let v = tables.1[key] { … } // assume returns out of here on success</div></div><div class=""><br class=""></div><div class="">…but that’s obviously putting a lot of pressure on the compiler to convert the `for index in #count(tables) { … }` code into something equivalent-but-reasonable.</div><div class=""><br class=""></div><div class="">I’ll be sure to look @ at the proposed `fold` in this light.</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">This is interesting. Might it be possible with to accomplish this with existentials (this is sort of a cross-reference to a different proposal from the generics manifest)? An existential type as described below would work for any pack where all the elements were constrained in the same way. Not sure if it could be made to work in the case where the types in the pack are related to each other (as proposed earlier).</div><div class=""><br class=""></div><div class="">struct ChainSequenceIterator&lt;E, S… where S:Sequence, S.Iterator.Element == E&gt; {</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// A single variable that contains each iterator in turn; specific type doesn't matter as long as the element is E</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>private var iterator : Any&lt;Iterator where .Element == E&gt;?</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// ...</div><div class="">}&nbsp;</div></div></div></blockquote><div><br class=""></div>Actually yes, I hadn’t thought of that and you could make it work in this case (although perhaps with some indirection overhead? and it seems also with some additional state tracking to know which iterator you actually have).</div><div><br class=""></div><div>Where I’m not as sure is for something like a `ChainCollectionIndex` (same `stuff from A, then stuff from B, etc” concept, but for A, B collections, and so on).</div><div><br class=""></div><div>That’s more clearly a case where what you *want* ideally is something like this:</div><div><br class=""></div><div>&nbsp; struct ChainCollection2&lt;A:Collection,B:Collection&gt; {</div><div>&nbsp; &nbsp; let a: A; let b: B&nbsp;</div><div>&nbsp; }</div><div><br class=""></div><div>&nbsp; struct ChainCollectionIndex2&lt;A:Comparable,B:Comparable&gt; {</div><div>&nbsp; &nbsp; private var sourceIndex: Sum2&lt;A,B&gt; // e.g. (A | B)</div><div>&nbsp; }</div><div><br class=""></div><div>…since to implement the APIs you need A and A.Index and B and B.Index to "match up". It’s probably possible here to do something like this instead:</div><div><br class=""><div><div>&nbsp; struct ChainCollectionIndex2&lt;A:Comparable,B:Comparable&gt; {</div><div>&nbsp; &nbsp; private var boxedIndex: Box&lt;Any&gt; // actually either Box&lt;A&gt; or Box&lt;B&gt;</div><div>&nbsp; &nbsp; private var whichIndex: AOrB // (E.G. enum ilke IndexFromA | IndexFromB)</div><div>&nbsp; }</div><div class=""><br class=""></div><div class="">…with a lot of casting and so on, and perhaps also with existentials (and/or casting and open-as), but it’d be *cleaner* with the sum, still.</div><div class=""><br class=""></div><div class="">Either way you’re right that e.g. existentials and similar + state flags can cover a lot of these uses.</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">D: Make Parameter-Packs Named</div><div class=""><br class=""></div><div class="">I understand the appeal of the `…T`-style syntax, but I’d at least consider giving parameter-packs a more-concrete existence, e.g. something like this:</div><div class=""><br class=""></div><div class="">&nbsp; // strawman declaration syntax:</div><div class="">&nbsp; struct Foo&lt;I,J,K#ParameterPack&gt; {</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; // `K` here will refer to the variadic parameter-pack itself;</div><div class="">&nbsp; &nbsp; // cf the `typealias` below , but basically K ~ the tuple of its types</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; typealias KValueTuple = #tuple(K) // == tuple of values of type K.0, K.1, etc.)</div><div class="">&nbsp; &nbsp; typealias KTypeTyple - #typeTuple(K) // == tuple of types like K.0, K.1</div><div class="">&nbsp; &nbsp; typealias FirstK = #first(K)&nbsp;</div><div class="">&nbsp; &nbsp; typealias LastK = #last(K)&nbsp;</div><div class="">&nbsp; &nbsp; static var kArity: Int { return #count(K) }&nbsp;</div><div class="">&nbsp; &nbsp; // and so on</div><div class=""><br class=""></div><div class="">&nbsp; }</div><div class=""><br class=""></div><div class=""><div class="">&nbsp; // straw man point-of-use syntax, can be adjusted of course:</div></div><div class="">&nbsp; let concreteFoo = Foo&lt;I,J,K:(K0,K1,K2,…,Kn)&gt;</div><div class=""><br class=""></div><div class="">…which complicates the grammar, but IMHO feels a lot nicer than having a lot of "implicit rules" about what `…` means and so on.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I think it makes sense to make pack usage explicit. I think the dots at site of declaration don't really cause trouble, though, and are a little nicer to read than T#ParameterPack.</div></div></div></blockquote><div><br class=""></div><div>I agree #ParameterPack is awful and that T… at the declaration site is not a big deal.</div><div><br class=""></div><div>What I don’t like is not having a way to refer to the pack itself other than via its “placeholder type” with some dots.</div><div><br class=""></div><div>It also seems nicer to express things like a pack fusion with names for packs, but again in fairness it’s not terrible:</div><div><br class=""></div><div>&nbsp; struct Foo&lt;T…&gt; {</div><div>&nbsp; }</div><div><br class=""></div><div>&nbsp; func +++&lt;T…,U…&gt;(lhs: Foo&lt;T…&gt;, rhs: Foo&lt;U…&gt;) -&gt; Foo&lt;#fuse(T…,U…)&gt;&nbsp;</div><div><br class=""></div><div>…so I’m not sure what I think on this.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On May 28, 2016, at 3:03 PM, Austin Zheng via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">Hello swift-evolution,<div class=""><br class=""></div></div></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></div></blockquote></div><br class=""></body></html>