<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 Mar 2, 2016, at 9:24 PM, Slava Pestov &lt;<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Doug,<div class=""><br class=""></div><div class="">I’m really happy to see this written up. I’m wondering if adding a bit more detail on some of the bigger items would help scope the work.</div><div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 2, 2016, at 5:22 PM, Douglas Gregor 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=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><i style="font-size: 14px;" class="">Nested generics</i></div><div class=""><br class=""></div><div class="">Currently, a generic type cannot be nested within another generic type, e.g.</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">struct X&lt;T&gt; {</font></div><div class=""><font face="Menlo" class="">&nbsp; struct Y&lt;U&gt; { } &nbsp;<i class="">// currently ill-formed, but should be possible</i></font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">There isn’t much to say about this: the compiler simply needs to be improved to handle nested generics throughout.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes! :-)</div><div class=""><br class=""></div><div class="">For nested generic functions, the only limitation today is that nested functions cannot capture values from an outer scope if they also have a generic signature of their own. I have some patches implementing this but I haven’t had a chance to work on them for a while.</div><div class=""><br class=""></div><div class="">Nested generic types require some runtime support but I believe Sema mostly models them correctly — we recently fixed a lot of compiler crashes related to this. Shouldn’t be too much work to get both of these into Swift 3 :)</div><div class=""><br class=""></div><div class="">However there are a crazier things we should figure out:</div><div class=""><br class=""></div><div class="">a) Generic types nested inside generic functions have been a source of compiler_crashers because the inner generic signature has more primary parameters than the bound generic type, due to “captures". For example, if you have something like:</div><div class=""><br class=""></div><div class="">func foo&lt;T&gt;() {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>struct S&lt;U&gt; {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>let p: (T, U)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class="">}</div><div class=""><br class=""></div><div class="">The metatype for S&lt;U&gt; should also “capture” the type parameter T. In particular it seems that invocations of foo() with different concrete types bound to T will produce distinct S types. Sema doesn’t really model this well right now, I think — it just has some hacks to avoid crashing. Also I wonder what this means if S conforms to a protocol. There might be representational issues with the conformance in the runtime, or at least the captured type has to be stashed somewhere.</div></div></div></div></div></blockquote><div><br class=""></div><div>Right. Our modeling for this is to essentially pretend that T isn’t part of the generic signature of S, which is wrong. Rather, we want T to be part of the generic signature, but that it’s bound to a particular type within the context.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class=""><br class=""></div><div class="">b) There’s also the case of types nested inside protocols. Do we ever want to allow this (my opinion is ’no’), and if so, what does it mean exactly?</div><div class=""><br class=""></div><div class="">protocol Collection {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>associatedtype ElementType</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>struct Iterator {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>let e: ElementType</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class="">}</div></div></div></div></div></blockquote><div><br class=""></div><div>Presumably you get a different Iterator for each type that conforms to Collection, but I agree that we probably don’t want this.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class="">c) Protocols nested inside functions and other types should probably never be allowed. There might be some latent crashes because of Sema assumptions that the Self type is at depth 0, or cases where diagnostics are not emitted.</div></div></div></div></div></blockquote><div><br class=""></div><div>Agreed. Protocols nested within anything should be banned.</div><div><br class=""></div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class=""><br class=""></div></div><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><span style="font-size: 14px;" class=""><i class="">Concrete same-type requirements</i><br class=""></span></div><div class=""><br class=""></div><div class=""><div class="">Currently, a constrained extension cannot use a same-type constraint to make a type parameter equivalent to a concrete type. For example:</div></div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">extension Array <b class="">where Element == String</b> {</font></div><div class=""><font face="Menlo" class="">&nbsp; func makeSentence() -&gt; String {</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; // uppercase first string, concatenate with spaces, add a period, whatever</font></div><div class=""><font face="Menlo" class="">&nbsp; }</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">This is a highly-requested feature that fits into the existing syntax and semantics. Note that one could imagine introducing new syntax, e.g., extending “Array&lt;String&gt;”, which gets into new-feature territory: see the section on “Parameterized extensions”.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Do we already support same-type constraints between two primary generic parameters or should this be added in as well?</div></div></div></div></div></blockquote><div><br class=""></div><div>That could also be added as part of this.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><i class="" style="font-size: 14px;">*Typealiases in protocols and protocol extensions</i></div><div class=""><br class=""></div><div class=""><div class="">Now that associated types have their own keyword (thanks!), it’s reasonable to bring back “typealias”. Again with the Sequence protocol:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">protocol Sequence {</font></div></div></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; associatedtype Iterator : IteratorProtocol</font></div></div></div><div class=""><font face="Menlo" class="">&nbsp; typealias Element = Iterator.Element &nbsp; //&nbsp;rejoice! now we can refer to SomeSequence.Element rather than SomeSequence.Iterator.Element</font></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote></div></div></blockquote><div class=""><br class=""></div>If we decide to pass ‘Element’ as a top-level metadata parameter, this could be used an optimization hint, and would also have resilience implications.</div></div></div></div></blockquote><div><br class=""></div><div>By top-level metadata parameter, you mean create an entry for Element in the witness table? That would eliminate one hop when accessing the metadata,</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">Conditional conformances are a potentially very powerful feature. One important aspect of this feature is how deal with or avoid overlapping conformances. For example, imagine an adaptor over a Sequence that has conditional conformances to Collection and MutableCollection:</div></div></div></blockquote><div class=""><br class=""></div>Would it be enough to prohibit defining multiple conditional conformances to the same protocol for the same base type but with different ‘where’ clauses?</div></div></div></div></blockquote><div><br class=""></div><div>It’s more nuanced than that, because we need to consider the implied conformances as well.</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">protocol A { }</font></div></div><div><div><font face="Menlo" class="">protocol B : A { }</font></div></div><div><div><font face="Menlo" class="">protocol C : A { }</font></div></div><div><div><font face="Menlo" class=""><br class=""></font></div></div><div><div><font face="Menlo" class="">struct X&lt;T&gt; { }</font></div></div><div><div><font face="Menlo" class="">extension X : B where T : B { } // implies a conformance to A</font></div></div><div><div><div><font face="Menlo" class="">extension X : C where T : C { } // problem: also implies a conformance to A</font></div></div></div></blockquote><div><div><div class=""><br class=""></div></div><div>Neither conformance to A is clearly “better”, because these constrained extensions are disjoint. The fix for this is actually to *add* an explicit conformance:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">extension X : A where T : A { } // okay: here’s where the conformance to A lives</font></div></div></blockquote><div><div><br class=""></div>The important part here is that both the “”B” and “C” extensions have requirements that subsume the requirements of A, so rather than introduce their own implied conformances to A, they leverage the existing conformance from the less-specialized constrained extension.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">public struct ZipIterator&lt;... <b class="">Iterators</b> : IteratorProtocol</font><span style="font-family: Menlo;" class="">&gt; : Iterator { &nbsp;<i class="">// zero or more type parameters, each of which conforms to IteratorProtocol</i></span></div></div></blockquote></div></blockquote><div class=""><br class=""></div>Would this make sense too:</div><div class=""><br class=""></div><div class="">struct ZipIterator&lt;… Iterators where Iterators : IteratorProtocol&gt;</div><div class=""><br class=""></div><div class="">I’m wondering if we can replace current varargs with a desugaring along the lines of:</div><div class=""><br class=""></div><div class="">func vararg(let a: A…) {</div><div class=""><br class=""></div><div class="">}</div><div class=""><br class=""></div><div class="">func vararg&lt;… T where T == A&gt;(let a: (T…)) { … }</div></div></div></div></blockquote><div><br class=""></div>We could treat it that way.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">Currently, varargs have a static number of arguments at the call site — instead of constructing an array, they could be passed as a tuple value, which would presumably be stack allocated at the call site. Together with a runtime entry point to get tuple metadata from a single element type repeated N times, this might be more efficient than varargs are now, where as far as I understand the array is allocated on the heap by the caller.</div></div></div></div></blockquote><div><br class=""></div><div>We could just decide that the “array” we get in the callee is only really materialized to the heap if it’s going to escape somewhere, and optimize for the common case where we can do stack allocation in the caller and the callee just directly consumes the result. In other words, I suspect we can optimize this case well (possibly better) without the desugaring. And it might affect our calling convention, so I’d want to make that decision long before we would get variadic generics.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">There are some natural bounds here: one would need to have actual structural types. One would not be able to extend every type:</div></blockquote><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">extension&lt;T&gt; T { <i class="">// error: neither a structural nor a nominal type</i></font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote></div></blockquote><div class=""><br class=""></div>Extending Any or AnyObject doesn’t seem too far-fetched, though, and almost feels like an artificial restriction at this point. Has nobody ever wanted this?</div></div></div></div></blockquote><div><br class=""></div><div>It’s been requested. Perhaps I shouldn’t be so quick to dismiss it.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">And before you think you’re cleverly making it possible to have a conditional conformance that makes every type T that conforms to protocol P also conform to protocol Q, see the section "Conditional conformances via protocol extensions”, below:</div></div></blockquote><div class=""><br class=""></div>What about self-conforming protocols? I’m willing to bet most people don’t use static methods in protocols, so it seems unnatural that a protocol type cannot be bound to a generic parameter constrained to that protocol type. Today on Twitter we had someone doing something like this:</div><div class=""><br class=""></div><div class="">protocol BaseProto {}</div><div class="">protocol RefinedProto : BaseProto {}</div><div class=""><br class=""></div><div class="">func doStuff&lt;T : BaseProto&gt;(let a: [T]) {}</div><div class=""><br class=""></div><div class="">getRefined() -&gt; [RefinedProto]</div><div class=""><br class=""></div><div class="">doStuff(getRefined()) // doesn’t type check!</div><div class=""><br class=""></div><div class="">Of course the underlying reason is that BaseProto does not conform to _itself_, which has nothing to do with RefinedProto.</div><div class=""><br class=""></div><div class="">There are tricky representational issues with self-conforming protocols, especially class-constrained ones — we expect an instance of a class-constrained generic parameter to be a single retainable pointer, which is not the case if it is an existential with an associated witness table. But if we can figure this out, it would smooth over a sharp edge in the language that confuses people who are not intimately familiar with how existential types are represented (ie, everybody except for us :) ).</div><div class=""><br class=""></div><div class="">This is different from opening existentials, because here we’re binding T to RefinedProto and cannot simultaneously open everything in the array…</div></div></div></div></blockquote><div><br class=""></div><div>Right.&nbsp;</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><i class="" style="font-size: 14px;">Specifying type arguments for uses of generic functions</i></div><div class=""><br class=""></div><div class="">The type arguments of a generic function are always determined via type inference. For example, given:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">func f&lt;T&gt;(t: T)</font></div></blockquote><div class=""><br class=""></div><div class="">one cannot directly specify T: either one calls “f” (and T is determined via the argument’s type) or one uses “f” in a context where it is given a particular function type (e.g., “let x: (Int) -&gt; Void = f” &nbsp;would infer T = Int). We could permit explicit specialization here, e.g.,</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">let x = f&lt;Int&gt; // x has type (Int) -&gt; Void</font></div></blockquote></div></blockquote><div class=""><br class=""></div>Are higher-kinded function values worth discussing too?</div></div></div></div></blockquote><div><br class=""></div>I’m not particularly motivated by them.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">if let storedInE1 = e1 openas T { &nbsp; &nbsp; // T is a the type of storedInE1, a copy of the value stored in e1</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">&nbsp; if let storedInE2 = e2 as? T { &nbsp; &nbsp; &nbsp;// is e2 also a T?</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">&nbsp; &nbsp; if storedInE1 == storedInE2 {&nbsp;… } // okay: storedInT1 and storedInE2 are both of type T, which we know is Equatable</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">&nbsp; }</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">}</font></blockquote></div></div></blockquote><div class=""><br class=""></div>I’m worried that this is not really correct with inheritance. If e1 is an instance of SubClass, and e2 is an instance of SuperClass with SubClass : SuperClass, then your operation is no longer symmetric. Heterogeneous equality just seems like a pain in general.</div></div></div></div></blockquote><br class=""></div><div>Indeed, this is a problem with my example! We would have to check in both directions: e1 could contain a subclass of e2 or vice versa.</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div><br class=""></div><br class=""></body></html>