<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="">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><blockquote type="cite" class=""><div class="">On Mar 2, 2016, at 5:22 PM, Douglas Gregor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> 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<T> {</font></div><div class=""><font face="Menlo" class=""> struct Y<U> { } <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><br class=""></div><div>Yes! :-)</div><div><br class=""></div><div>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><br class=""></div><div>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><br class=""></div><div>However there are a crazier things we should figure out:</div><div><br class=""></div><div>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><br class=""></div><div>func foo<T>() {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>struct S<U> {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>let p: (T, U)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div>}</div><div><br class=""></div><div>The metatype for S<U> 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><br class=""></div><div>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><br class=""></div><div>protocol Collection {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>associatedtype ElementType</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>struct Iterator {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>let e: ElementType</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div>}</div><div><br class=""></div><div>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><br class=""></div></div><div><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=""> func makeSentence() -> String {</font></div><div class=""><font face="Menlo" class=""> // uppercase first string, concatenate with spaces, add a period, whatever</font></div><div class=""><font face="Menlo" class=""> }</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<String>”, which gets into new-feature territory: see the section on “Parameterized extensions”.</div></div></div></blockquote><div><br class=""></div><div>Do we already support same-type constraints between two primary generic parameters or should this be added in as well?</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=""><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=""> associatedtype Iterator : IteratorProtocol</font></div></div></div><div class=""><font face="Menlo" class=""> typealias Element = Iterator.Element // 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><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><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=""><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><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><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><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">public struct ZipIterator<... <b class="">Iterators</b> : IteratorProtocol</font><span style="font-family: Menlo;" class="">> : Iterator { <i class="">// zero or more type parameters, each of which conforms to IteratorProtocol</i></span></div></div></blockquote></div></blockquote><div><br class=""></div>Would this make sense too:</div><div><br class=""></div><div>struct ZipIterator<… Iterators where Iterators : IteratorProtocol></div><div><br class=""></div><div>I’m wondering if we can replace current varargs with a desugaring along the lines of:</div><div><br class=""></div><div>func vararg(let a: A…) {</div><div><br class=""></div><div>}</div><div><br class=""></div><div>func vararg<… T where T == A>(let a: (T…)) { … }</div><div><br class=""></div><div>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><br class=""></div><div><br 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<T> 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><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><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><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><br class=""></div><div>protocol BaseProto {}</div><div>protocol RefinedProto : BaseProto {}</div><div><br class=""></div><div>func doStuff<T : BaseProto>(let a: [T]) {}</div><div><br class=""></div><div>getRefined() -> [RefinedProto]</div><div><br class=""></div><div>doStuff(getRefined()) // doesn’t type check!</div><div><br class=""></div><div>Of course the underlying reason is that BaseProto does not conform to _itself_, which has nothing to do with RefinedProto.</div><div><br class=""></div><div>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><br class=""></div><div>This is different from opening existentials, because here we’re binding T to RefinedProto and cannot simultaneously open everything in the array…</div><div><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<T>(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) -> Void = f” 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<Int> // x has type (Int) -> Void</font></div></blockquote></div></blockquote><div><br class=""></div>Are higher-kinded function values worth discussing too?</div><div><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=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class=""><br class="">if let storedInE1 = e1 openas T { // 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=""> if let storedInE2 = e2 as? T { // is e2 also a T?</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class=""> if storedInE1 == storedInE2 { … } // 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=""> }</font></blockquote><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><font face="Menlo" class="">}</font></blockquote></div></div></blockquote><div><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><br class=""></div><div>Slava</div><div><br class=""></div><br class=""></div></body></html>