<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Nov 21, 2017 at 8:43 AM Howard Lovatt via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">In Scala they just define Tuple1<A>, Tuple2<A, B>, ... up to 22 (I think). Eliminates the need for variadic generics and works fine in practice in Scala. <div><br></div><div>In Swift this approach is possibly unacceptable, since having to write:</div><div><br></div><div> extension Tuple1 ...</div><div> extension Tuple2 ...</div><div> ...</div><div> extension Tuple22 ...</div><div><br></div><div>Is a real pain. </div><div><br></div><div>However if we added variadic generics, Tuple<T...>, then we would also need a tuple to become a Collection (or some minimal subset of), e.g.:</div><div><br></div><div> extension Tuple: Equatable where T: Equatable {</div><div> static <span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637kwd" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">func</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> </span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">==</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> </span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">(</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">lhs</span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">:</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> Tuple</span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">,</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> rhs</span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">:</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> Tuple</span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">)</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> </span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">-></span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> </span><span class="m_8452324628547245637typ" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">Bool</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> </span><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline">{</span></span></div><div><span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> guard lhs.count == rhs.count else {</span></span></div><div><span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> return false</span></span></div><div><span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> }</span></span></div><div><span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> for i in 0 ..< lhs.count {</span></span></div><div><div><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline;background-color:rgba(255,255,255,0)"> guard lhs[i] == rhs[i] else {</span></div><div><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline;background-color:rgba(255,255,255,0)"> return false</span></div><div><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline;background-color:rgba(255,255,255,0)"> }</span></div></div><div><span style="background-color:rgba(255,255,255,0)"><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> }</span></span></div><div><span class="m_8452324628547245637kwd" style="font-style:inherit;font-variant-caps:inherit;background-color:rgba(255,255,255,0);box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> return</span><span class="m_8452324628547245637pln" style="font-style:inherit;font-variant-caps:inherit;background-color:rgba(255,255,255,0);box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> true</span></div><div><span class="m_8452324628547245637pun" style="font-style:inherit;font-variant-caps:inherit;background-color:rgba(255,255,255,0);box-sizing:border-box;margin:0px;padding:0px;border:0px;font-stretch:inherit;line-height:inherit;vertical-align:baseline"> }</span></div><div> }</div><div><br></div></div></blockquote><div><br></div><div>It's a bit more complex than that—saying `where T: Equatable` feels off because `T` here isn't a single type. A syntax like `T...: Equatable` to mean "all arguments in the parameter pack conform to Equatable" might be clearer.</div><div><br></div><div>Adding Collection conformance is also problematic because tuples can be heterogeneous. If you have Tuple<Int, String, SomeClass>, what's the type of lhs[i]? It depends on i, which isn't going to work.</div><div><br></div><div>We'd probably need some syntax for destructuring tuples into a "first" element and "rest" tuple of arity N–1 so that equality (and other operations) could be implemented recursively, statically at compile time.</div><div><br></div><div>Of course, all of this gets dangerously into the realm of C++ template metaprogramming horrors. :) Hopefully we can come up with less obtuse solutions/syntax for Swift.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div></div><div>Note how the tuple is treated like a collection. The compiler magic would be to make a Tuple a collection, which is more ‘magic’ than ‘magically’ adding Hashable :).</div><div><br></div><div>Despite the profusion of magic, variadic generics and Tuple collection additions are my favourite option. </div></div><div dir="auto"><div><br><br><div id="m_8452324628547245637AppleMailSignature">-- Howard. </div></div></div><div dir="auto"><div><div><br>On 21 Nov 2017, at 1:17 pm, Chris Lattner via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br><br></div><blockquote type="cite"><div>Yes, I agree, we need variadic generics before we can have tuples conform :-(<div><br></div><div>At the end of the day, you want to be able to treat “(U, V, W)” as sugar for Tuple<U,V,W> just like we handle array sugar. When that is possible, Tuple is just a type like any other in the system (but we need variadics to express it).</div><div><br></div><div>Once you have that, then you could write conformances in general, as well as conditional conformances that depend on (e.g.) all the element types being equatable.</div><div><br></div><div><br></div><div>We also need that to allow functions conform to protocols, because functions aren’t "T1->T2” objects, the actual parameter list is an inseparable part of the function type, and the parameter list needs variadics.</div><div><br></div><div>-Chris</div><div><br></div><div><div><blockquote type="cite"><div>On Nov 20, 2017, at 6:10 PM, Slava Pestov <<a href="mailto:spestov@apple.com" target="_blank">spestov@apple.com</a>> wrote:</div><br class="m_8452324628547245637Apple-interchange-newline"><div><div style="word-wrap:break-word;line-break:after-white-space">Ignoring synthesized conformances for a second, think about how you would manually implement a conformance of a tuple type to a protocol. You would need some way to statically “iterate” over all the component types of the tuple — in fact this is the same as having variadic generics.<div><br></div><div>If we had variadic generics, we could implement tuples conforming to protocols, either by refactoring the compiler to allow conforming types to be non-nominal, or by reworking things so that a tuple is a nominal type with a single variadic generic parameter.</div><div><br></div><div>Slava<br><div><br><blockquote type="cite"><div>On Nov 20, 2017, at 9:06 PM, Tony Allevato via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_8452324628547245637Apple-interchange-newline"><div><div dir="ltr">This is something I've wanted to look at for a while. A few weeks ago I pushed out <a href="https://github.com/apple/swift/pull/12598" target="_blank">https://github.com/apple/swift/pull/12598</a> to extend the existing synthesis to handle structs/enums when a field/payload has a tuple of things that are Equatable/Hashable, and in that PR it was (rightly) observed, as Chris just did, that making tuples conform to protocols would be a more general solution that solves the same problem you want to solve here.<div><br></div><div>I'd love to dig into this more, but last time I experimented with it I got stuck on places where the protocol conformance machinery expects NominalTypeDecls, and I wasn't sure where the right place to hoist that logic up to was (since tuples don't have a corresponding Decl from what I can tell). Any pointers?</div></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Nov 20, 2017 at 5:51 PM Chris Lattner via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">On Nov 20, 2017, at 5:48 PM, Kelvin Ma <<a href="mailto:kelvin13ma@gmail.com" target="_blank">kelvin13ma@gmail.com</a>> wrote:</div><div style="word-wrap:break-word"><div><blockquote type="cite"><div><div dir="ltr">the end goal here is to use tuples as a compatible currency type, to that end it makes sense for these three protocols to be handled as “compiler magic” and to disallow users from manually defining tuple conformances themselves. i’m not a fan of compiler magic, but Equatable, Hashable, and Comparable are special because they’re the basis for a lot of standard library functionality so i think the benefits of making this a special supported case outweigh the additional language opacity.<br></div></div></blockquote><div><br></div></div></div><div style="word-wrap:break-word"><div><div>I understand your goal, but that compiler magic can’t exist until there is something to hook it into. Tuples can’t conform to protocols right now, so there is nothing that can be synthesized.</div></div></div><div style="word-wrap:break-word"><div><div><br></div><div>-Chris</div></div></div><div style="word-wrap:break-word"><div><div><br></div><br><blockquote type="cite"><div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 20, 2017 at 8:42 PM, Chris Lattner <span dir="ltr"><<a href="mailto:clattner@nondot.org" target="_blank">clattner@nondot.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><span><blockquote type="cite"><div>On Nov 20, 2017, at 5:39 PM, Kelvin Ma via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_8452324628547245637m_432242003226007445m_2255698535222666290Apple-interchange-newline"><div><div dir="ltr"><div><div>when <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0185-synthesize-equatable-hashable.md" target="_blank">SE-185</a> went through swift evolution, it was agreed that the <a href="https://www.mail-archive.com/swift-evolution@swift.org/msg26162.html" target="_blank">next logical step</a> is synthesizing these conformances for tuple types, though it was left out of the original proposal to avoid mission creep. I think now is the time to start thinking about this. i’m also tacking on <span style="font-family:monospace,monospace">Comparable</span> to the other two protocols because there is precedent in the language from <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0015-tuple-comparison-operators.md" target="_blank">SE-15</a> that tuple comparison is something that makes sense to write.<br><br></div>EHC conformance is even more important for tuples than it is for structs because tuples effectively have no workaround whereas in structs, you could just manually implement the conformance. </div></div></div></blockquote><div><br></div></span><div>In my opinion, you’re approaching this from the wrong direction. The fundamental problem here is that tuples can’t conform to a protocol. If they could, synthesizing these conformances would be straight-forward.</div><div><br></div><div>If you’re interested in pushing this forward, the discussion is “how do non-nominal types like tuples and functions conform to protocols”?</div><span class="m_8452324628547245637m_432242003226007445HOEnZb"><font color="#888888"><div><br></div><div>-Chris</div><div><br></div><br><br></font></span></div><br></div></blockquote></div><br></div>
</div></blockquote></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>
_______________________________________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div>