<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="">On May 27, 2016, at 7:08 AM, Thorsten Seitz <<a href="mailto:tseitz42@icloud.com" class="">tseitz42@icloud.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><br class="Apple-interchange-newline">Am 25.05.2016 um 22:16 schrieb Matthew Johnson via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>>:</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 <<a href="mailto:brent@architechies.com" class="">brent@architechies.com</a>> 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<ElementConstraint> = Collection where .Element: ElementConstraint<br class=""><br class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>let value: Any<HashableAndComparable> = 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<C: CollectionOfConforming<Integer>>(numbers: C) -> 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). It could be similar to what you have, but slightly more generalized.<br class=""><br class=""><br class="">func sum<br class=""> <T, C1, C2<br class=""> where C1: Sequence, C2: Sequence, C1.Iterator.Element == T, C2.Iterator.Element == T><br class=""> (c1: C1, c2: C2, op: (T, T) -> T) -> [T] {<br class=""> 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=""> <S1, S2 where SameElementSequences<S1, S2>><br class=""> (s1:S1, s2: S2, op: (S1.Element, S2.Element) -> S1.Element) -> [S1.Element] {<br class=""> return zip(s1, s2).map(op)<br class="">}<br class=""><br class="">So what syntax do we use to define something like `SameElementSequences<S1, S2 >`? It is effectively a predicate that returns true if all of the constraints it defines are satisfied. 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 =<span class="Apple-converted-space"> </span><br class=""> S1: Sequence, S2: Sequence<br class=""> where S1.Element == S2.Element<br class=""></div></div></blockquote><div class=""><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></blockquote><div><br class=""></div><div>Great!</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">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></blockquote><div><br class=""></div><div>Yeah, I wasn’t trying to provide the best / most general design for `zipMap`. I chose a signature that would demonstrate how you might want to abstract over constraints that apply to more than one constrainee. It was the first thing that came to mind. :-)</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">func zipMap<S1: Sequence, S2: Sequence, Result></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><span class="Apple-tab-span" style="white-space: pre;">        </span>(s1: S1, s2: S2, op: (S1.Element, S2.Element) -> Result) -> [Result] {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><span class="Apple-tab-span" style="white-space: pre;">        </span>return zip(s1, s2).map(op)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">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 style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">func subtract<S1, S2, E where SequencesOf<E, S1, S2>, E: Equatable></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><span class="Apple-tab-span" style="white-space: pre;">        </span>(s1: S1, s2: S2) -> [E] {</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// answer array containing all elements of s1 which are not in s2</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">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 style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">constraint SequencesOf<Element, S1, S2> =<br class=""> S1: Sequence, S2: Sequence<br class=""> where S1.Element == Element, S2.Element == Element</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">Regardless whether Element, S1 or S2 are concrete types or type parameters, the constraint can simply be checked whether it holds.</div></div></blockquote><div><br class=""></div><div>The reason it matters is that you *must* pass something that can be constrained to a `Constrainee` argument. You *cannot* pass a concrete type. This could be inferred, but I think that would fall into the same category as inference across a function signature, which Swift is specifically avoiding. Thus the “kind” specification.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">Maybe we could change the syntax a little bit:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><b class="">constraint</b><span class="Apple-converted-space"> </span>SequencesOf<Element, S1, S2><span class="Apple-converted-space"> </span><b class="">where</b><span class="Apple-converted-space"> </span>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 class=""><b class="">constraint</b><span class="Apple-converted-space"> </span>SequencesOf<Element, S1: Sequence, S2: Sequence> <b class="">where</b><span class="Apple-converted-space"> </span>S1.Element == Element, S2.Element == Element</div></div><div class=""><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<Element, S> = 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<Element, S> where S: Sequence, Element == S.Element</div></div></div></blockquote><div><br class=""></div><div>I avoided angle brackets on the arguments because I think it’s more readable without them. But there is a good case to be made that angle brackets should be used for compile-time parameters in Swift. This syntax works for me. </div><div><br class=""></div><div>One thing that just occurred to me when looking at your example:</div><div><br class=""></div><div>constraint SequencesOf<Element, S1: <b class="">Sequence</b>, S2: <b class="">Sequence</b>> where S1.Element == Element, S2.Element == Element</div><div><br class=""></div><div>I wonder if we would ever need the ability to pass a constrained but concrete type to a constraint abstraction. I can’t quickly think of any examples where we would. If we don’t need the ability to do this, we could easily infer that `S1` and `S2` are of kind `Constrainee` because they are constrained in the signature. We could also say that the default kind is `Type`. This would minimize the need to state and think explicitly about kinds.</div><div><br class=""></div><div>-Matthew</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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="">-Thorsten</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: 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=""><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. 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) -> 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=""> S1: Sequence, S2: Sequence<br class=""> where S1.Element == Element, S2.Element == Element<br class=""><br class="">Used like this:<span class="Apple-converted-space"> </span><br class=""><br class="">func intZipMap<br class=""> <S1, S2 where SequencesOf<Int, S1, S2>><br class=""> (s1:S1, s2: S2, op: (Int) -> Int) -> [Int] {<br class=""> 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. 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. 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="">--<span class="Apple-converted-space"> </span><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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></div></blockquote></div></div></blockquote></div><br class=""></body></html>