<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=""><br class=""><div><blockquote type="cite" class=""><div class="">Am 25.05.2016 um 22:16 schrieb Matthew Johnson via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt;:</div><br class="Apple-interchange-newline"><div class=""><div class=""><br class=""><blockquote type="cite" class="">On May 25, 2016, at 2:22 PM, Brent Royal-Gordon &lt;<a href="mailto:brent@architechies.com" class="">brent@architechies.com</a>&gt; wrote:<br class=""><br class=""><blockquote type="cite" class="">But if we are going to remove the ability to use typealiases bound to `Any` in constraints we need to introduce an alternative mechanism for factoring out constraints (hopefully a superior mechanism that can abstract over constraints that relate generic parameters to each other).<br class=""></blockquote><br class="">I could certainly imagine having, for instance, a `constraintalias` keyword:<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>constraintalias HashableAndComparable = Hashable, Comparable<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>constraintalias CollectionOfConforming&lt;ElementConstraint&gt; = Collection where .Element: ElementConstraint<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let value: Any&lt;HashableAndComparable&gt; = 123<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>func sum&lt;C: CollectionOfConforming&lt;Integer&gt;&gt;(numbers: C) -&gt; C.Iterator.Element {<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>return numbers.reduce(0, combine: +)<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class=""></blockquote><br class="">If we do something specific to generic constraints I would prefer to see something that generalizes to support cases where you want to accept two types that both conform to `Sequence`, `Collection`, etc and both have the same `Element` (or any other constraint that relates associated types from more than one type argument). &nbsp;It could be similar to what you have, but slightly more generalized.<br class=""><br class=""><br class="">func sum<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;T, C1, C2<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where C1: Sequence, C2: Sequence, C1.Iterator.Element == T, C2.Iterator.Element == T&gt;<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(c1: C1, c2: C2, op: (T, T) -&gt; T) -&gt; [T] {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return zip(c1, c2).map(op)<br class="">}<br class=""><br class="">This would allow me to write something along the lines of:<br class=""><br class="">func zipMap<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;S1, S2 where SameElementSequences&lt;S1, S2&gt;&gt;<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s1:S1, s2: S2, op: (S1.Element, S2.Element) -&gt; S1.Element) -&gt; [S1.Element] {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return zip(s1, s2).map(op)<br class="">}<br class=""><br class="">So what syntax do we use to define something like `SameElementSequences&lt;S1, S2 &gt;`? &nbsp;It is effectively a predicate that returns true if all of the constraints it defines are satisfied. &nbsp;It could be similar to what you have above, but we would need to allow for more than one “constrainee”.<br class=""><br class="">Maybe it would look something like this:<br class=""><br class="">constraint SameElementSequences S1, S2 = <br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S1: Sequence, S2: Sequence<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where S1.Element == S2.Element<br class=""></div></div></blockquote><div><br class=""></div>That’s a good example! Now this is beginning to make sense (or now I’m starting to understand it :-)</div><div><br class=""></div><div><br class=""></div><div>Side note: I would prefer zipMap being defined more generally which unfortunately renders this obsolete as an example for abstracted constraints as none are needed anymore:</div><div><br class=""></div><div>func zipMap&lt;S1: Sequence, S2: Sequence, Result&gt;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>(s1: S1, s2: S2, op: (S1.Element, S2.Element) -&gt; Result) -&gt; [Result] {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>return zip(s1, s2).map(op)</div><div>}</div><div><br class=""></div><div><br class=""></div><div>But we might want to create a generic subtraction function like follows which could make use of the constraint you defined further down:</div><div><br class=""></div><div>func subtract&lt;S1, S2, E where SequencesOf&lt;E, S1, S2&gt;, E: Equatable&gt;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>(s1: S1, s2: S2) -&gt; [E] {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>// answer array containing all elements of s1 which are not in s2</div><div>}</div><div><br class=""></div><div>Note that `E` is not a concrete type argument here. I’m not sure whether it makes sense to distinguish between `Type` and `Constrainee` as these kinds are simply a result of supplying either a concrete type or a type parameter:</div><div><br class=""></div><div>constraint SequencesOf&lt;Element, S1, S2&gt; =<br class="">&nbsp; &nbsp; &nbsp; &nbsp;S1: Sequence, S2: Sequence<br class="">&nbsp; &nbsp; &nbsp; &nbsp;where S1.Element == Element, S2.Element == Element</div><div><br class=""></div><div>Regardless whether Element, S1 or S2 are concrete types or type parameters, the constraint can simply be checked whether it holds.</div><div><br class=""></div><div><br class=""></div><div>Maybe we could change the syntax a little bit:</div><div><br class=""></div><div><div><b class="">constraint</b> SequencesOf&lt;Element, S1, S2&gt; <b class="">where</b> S1: Sequence, S2: Sequence, S1.Element == Element, S2.Element == Element</div><div class=""><br class=""></div><div class="">which might alternatively be written as:</div><div class=""><br class=""></div><div class=""><div><b class="">constraint</b> SequencesOf&lt;Element,&nbsp;S1: Sequence,&nbsp;S2: Sequence&gt;&nbsp;<b class="">where</b> S1.Element == Element, S2.Element == Element</div></div><div><br class=""></div><div class=""><br class=""></div><div class="">This would distinguish constraints better from typealiases. Otherwise a simple constraint would look like a typealias:</div><div class=""><br class=""></div><div class="">constraint SequenceOf&lt;Element, S&gt; = S where S: Sequence, Element == S.Element</div><div class=""><br class=""></div><div class="">vs.</div><div class=""><br class=""></div><div class="">constraint SequenceOf&lt;Element, S&gt; where S: Sequence, Element == S.Element</div></div><div><br class=""></div><div>-Thorsten</div><div><br class=""></div><div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class="">If we want to allow concrete types and higher order constraints to be passed we would have to specify “kinds” for the arguments to the constraints. &nbsp;We might say `Constrainee` for an argument that is getting constrained, `Type` for a concrete type argument and `Constraint` for a higher order constraint that applies to a single type and something like function type syntax for multi-argument higher order constraints: `(Type, Constrainee, Constraint) -&gt; Constraint` or something like that.<br class=""><br class="">This would let us do something like:<br class=""><br class="">constraint SequencesOf Element: Type, S1: Constrainee, S2: Constrainee =<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;S1: Sequence, S2: Sequence<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where S1.Element == Element, S2.Element == Element<br class=""><br class="">Used like this: <br class=""><br class="">func intZipMap<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;S1, S2 where SequencesOf&lt;Int, S1, S2&gt;&gt;<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(s1:S1, s2: S2, op: (Int) -&gt; Int) -&gt; [Int] {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return zip(s1, s2).map(op)<br class="">}<br class=""><br class="">We could allow shorthand for simple constraints where the “kinds” are omitted and assumed to be `Constrainee`.<br class=""><br class="">Ideally we would be able to overload constraints so we could use the name “SequencesOf” for a constraint that accepts three sequences, etc.<br class=""><br class="">I think I prefer `constraint` rather than `constraintalias` but am open to arguments for both of them.<br class=""><br class="">I like that you are allowed a `constraintalias` to be used as an existential. &nbsp;That would still work for single argument constraints in the generalized form I am suggesting.<br class=""><br class="">I’m just spitballing on syntax and keyword names here to try and communicate the capability that I think we should strive for. &nbsp;I’m interested in hearing everyone’s thoughts on this…<br class=""><br class="">-Matthew<br class=""><br class=""><blockquote type="cite" class=""><br class="">-- <br class="">Brent Royal-Gordon<br class="">Architechies<br class=""><br class=""></blockquote><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></div></blockquote></div><br class=""></body></html>