<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></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 Dec 11, 2015, at 3:22 PM, Drew Crawford 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=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">This is not really a well-thought-out proposal, but more of a brainstorm about if there is a good language-level solution.<div class=""><br class=""></div><div class="">A problem I frequently run into in Swift is the inability to use generic types as first-class "complete" types.<br class=""><div class=""><br class=""></div><div class="">Let's say that I have a protocol (with an associated types) and some structs that implement it (with different associated types).</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">//all good feature requests involve factories</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">protocol Factory {</div></div><div class=""><div class="">&nbsp; &nbsp; typealias Product</div></div><div class=""><div class="">&nbsp; &nbsp; func make() -&gt; Product</div></div><div class=""><div class="">&nbsp; &nbsp; var description : String { get }</div></div><div class=""><div class="">}</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">struct IntFactory : Factory {</div></div><div class=""><div class="">&nbsp; &nbsp; typealias product = Int</div></div><div class=""><div class="">&nbsp; &nbsp; func make() -&gt; Int { return 0 }</div></div><div class=""><div class="">&nbsp; &nbsp; var description : String { get { return "IntFactory" } }</div></div><div class=""><div class="">}</div></div><div class=""><div class=""><br class=""></div></div><div class=""><div class="">struct StringFactory : Factory {</div></div><div class=""><div class="">&nbsp; &nbsp; typealias product = String</div></div><div class=""><div class="">&nbsp; &nbsp; func make() -&gt; String { return "Hello world" }</div></div><div class=""><div class="">&nbsp; &nbsp; var description : String { get { return "StringFactory" } }</div></div><div class=""><div class="">}</div></div></blockquote></div></div></div></blockquote><div><br class=""></div><div>This seems like it would be addressed just by allowing Factory to be used as a dynamic type, with its Product type generalized to Any. We'll be set up to support that with some runtime work to store associated types in protocol witness tables (which is also necessary to fix cyclic conformances, one of our Swift 3 goals).</div><div><br class=""></div><div>-Joe</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="">Now it is easy to work on the underlying IntFactory and StringFactory:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">IntFactory().make() //static dispatch</div></div><div class=""><div class="">StringFactory().make() //static dispatch</div></div><div class=""><br class=""></div></blockquote>...but how do I write a function that works on either Factory? &nbsp;<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">func&nbsp;foo(a:&nbsp;Factory) {</div><div class="">&nbsp; &nbsp; a.make() //dynamic dispatch</div><div class="">} &nbsp;</div>error: protocol 'Factory' can only be used as a generic constraint because it has Self or associated&nbsp;type requirements</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class=""></blockquote>I could use generics:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">func&nbsp;foo&lt;A:&nbsp;Factory&gt;(a:&nbsp;A) {}</div></blockquote><br class=""><div class="">but now I need to bubble up generics all over the stack frame:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">func&nbsp;baz&lt;A:&nbsp;Factory&gt;(a:&nbsp;A){bar(a)}</div><div class="">func&nbsp;bar&lt;A:&nbsp;Factory&gt;(a:&nbsp;A){foo(a)}</div><div class="">func&nbsp;foo&lt;A:&nbsp;Factory&gt;(a:&nbsp;A) {a.make()}</div><div class=""><br class=""></div><div class="">class WhyIsthisGeneric&lt;A: Factory&gt; {</div><div class="">&nbsp; &nbsp; var a: A //because of an implementation detail of Factory, of course</div><div class="">}</div></blockquote><br class=""><div class="">I submit that this couples the implementation details of Factory too tightly to unrelated functions and methods (and perhaps entire classes that now become generic so I can create ivars).</div><div class=""><br class=""></div><div class="">Here's what I think is an elegant solution:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">typealias EitherFactory = union(Factory, [IntFactory, StringFactory])</div><div class="">let a : EitherFactory = IntFactory()</div><div class=""><div class="">func&nbsp;baz(a: EitherFactory){bar(a)}</div><div class="">func&nbsp;bar(a: EitherFactory){foo(a)}</div><div class="">func&nbsp;foo(a: EitherFactory){a.make()}</div></div><div class=""><br class=""></div></blockquote>The union function being a new builtin, that causes the compiler to automatically write this type behind the scenes:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">enum&nbsp;EitherFactory {</div><div class="">&nbsp; &nbsp;&nbsp;case&nbsp;intFactory(IntFactory)</div><div class="">&nbsp; &nbsp;&nbsp;case&nbsp;stringFactory(StringFactory)</div><div class="">&nbsp; &nbsp;&nbsp;</div><div class="">&nbsp; &nbsp;&nbsp;func&nbsp;make() -&gt;&nbsp;Any&nbsp;{</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch(self) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;.intFactory(let&nbsp;f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f.make()</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;.stringFactory(let&nbsp;f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f.make()</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}</div><div class="">&nbsp; &nbsp;&nbsp;}</div><div class="">&nbsp; &nbsp;&nbsp;</div><div class="">&nbsp; &nbsp;&nbsp;var&nbsp;description :&nbsp;String&nbsp;{</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;get&nbsp;{</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;switch(self) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;.intFactory(let&nbsp;f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f.description</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;case&nbsp;.stringFactory(let&nbsp;f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;f.description</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;}</div><div class="">&nbsp; &nbsp;&nbsp;}</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; var intFactory? : IntFactory {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; switch(self) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .intFactory(let f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return f</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div><div class=""><div class="">&nbsp; &nbsp; var stringFactory? : StringFactory {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; switch(self) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .StringFactory(let f):</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return f</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div></div><div class="">}</div></blockquote><div class=""><br class=""></div>This generated type is fully-specified, and so it may be used in any place a first-class type is allowed.<br class=""><div class=""><br class=""></div><div class="">Arguments in favor of this proposal:</div><div class=""><br class=""></div><div class="">1. &nbsp;It allows protocols with Self or associated type constraints to be promoted to "full" types in many practical usecases, (specifically, when the list of types can be enumerated, and this is always the case for protocols with private or internal visibility). &nbsp;</div><div class="">2. &nbsp;It allows the user to opt into the simplicity of dynamic dispatch with their generic types</div><div class="">3. &nbsp;Since the boilerplate is automatically generated, it updates automatically for new functions and methods added to the protocol, whereas my current solution is tedious, manual, and error-prone</div><div class="">4. &nbsp;The semantics allow for a (future) optimizer to optimize away the boilerplate. &nbsp;For example, if we write</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">let a: EitherFactory = IntFactory()</div><div class="">func&nbsp;foo(a: EitherFactory){a.make()}</div><div class="">foo(a)</div><div class=""><br class=""></div></blockquote>&nbsp; &nbsp; &nbsp;Our optimizer may emit a specialization "as if" I had bubbled generics:<blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><br class=""></div><div class="">let a: IntFactory = IntFactory()<br class="">func foo_specialized_intFactory (a: IntFactory){a.make()}<br class="">foo_specialized_intFactory(a)</div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div>&nbsp; &nbsp; Under this optimization the switch statement and the dynamic dispatch are eliminated. &nbsp;So the semantics allow "at least" dynamic dispatch performance, and "up to" static dispatch performance, given a strong optimizer</div><div class=""><div class=""><br class=""></div><div class=""><div class="">Motivating case:</div><div class=""><br class=""></div><div class="">This proposal arises (most recently) from the problem of trying to write code that is generic across IPv4 and IPv6. &nbsp;For example</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">final class Socket {</div></div><div class=""><div class="">&nbsp; &nbsp; func&nbsp;getsockname()&nbsp;-&gt; ???</div></div><div class=""><div class="">}</div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">In the IPv4 case this function should return `sockaddr_in`, but in the v6 case it should return `sockaddr_in6`. &nbsp;So this socket can only be represented as a protocol with associated type requirements, and so it cannot be trivially used e.g. as a function parameter, as an ivar, etc. &nbsp;This significantly complicates the implementation.</div><div class=""><br class=""></div><div class="">Incompleteness:</div><div class=""><br class=""></div><div class="">The full semantics of the union builtin are underspecified. &nbsp;</div><div class=""><br class=""></div><div class="">1. &nbsp;In the example, `make() -&gt; Int` and `make() -&gt; String` unify to `make() -&gt; Any`, but would `sequence() -&gt; CollectionType` and `sequence() -&gt; SequenceType` unify to &nbsp;`sequence() -&gt; Any`? &nbsp;Perhaps not.</div><div class="">2. &nbsp;What is the behavior if the arguments/return values of a function are themselves unions?</div><div class=""><br class=""></div><div class="">And finally, would it be a better idea merely to promote generics to "full" types, without the use of an explicit union builtin? &nbsp;The approach here is more narrowly tailored, but that is not necessarily the right language design.</div><div class=""><br class=""><div class=""><div class=""><div class=""><br class=""></div><div class=""><br class=""></div></div></div></div></div></div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=RoDF4MveSEMYBIqIJA6ub1g8cOZ-2BVYvqV-2FqygPhjPn9roniX5MN7SqSEvjpCofmXYVObeXQbZil9-2BiC0Zs70iZRa4iWbb-2BBNInrAx3t8qC2wGDZqnM2CFiic8cWBMpdalZMGe5E81X6KVvkfNF3LZQjBM9oiNLuAiZaJYar5acY6HNAlLCn14k4dMx3JLh8O9nkK0Vrb2BOmg5L7ZKn-2B6AF36P6Z6fj8Ls4tnWZp0zE-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;" class="">
</div>
_______________________________________________<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></blockquote></div><br class=""></body></html>