<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 Feb 6, 2017, at 10:06 AM, 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=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: 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">On Feb 5, 2017, at 5:36 PM, Abe Schneider 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi Robert,<div class=""><br class=""></div><div class="">Exactly. The benefit being that you can figure out the correct function to dispatch entirely at compile time. My understanding is that Swift doesn’t do this because of the associated code bloat (and it’s usually not necessary). However, I think there is some important functionality by allowing specialization to control dispatch in a similar way to c++. There is also the design element — my (fairly) succinct Tensor class that used to be ~300 lines is now already close to an additional 1000 lines of code and growing. While the type of library I’m writing might be outside of what is normally done with Swift, I suspect the design pattern I’m using crops up in other places, as well as the need for dispatch on specialization (e.g. <a href="http://stackoverflow.com/questions/41640321/extending-collection-with-a-recursive-property-method-that-depends-on-the-elemen" class="">http://stackoverflow.com/questions/41640321/extending-collection-with-a-recursive-property-method-that-depends-on-the-elemen</a>).</div></div></div></blockquote><div class=""><br class=""></div><div class="">You can’t figure out the correct function to dispatch entirely at compile time because Swift supports retroactive modeling. Let’s make this a super-simple example:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public protocol P { }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func f<T>(_:T) { print(“unspecialized”) }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func f<T: P>(_: T) { print(“specialized”) }</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func g<T>(_ x: T) { f(x) }</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module B</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>import A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>func testG(x: Int) {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> g(x) // the best we can statically do is print “unspecialized”; Int doesn’t conform to A.P, but...</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module C</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>import A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public extension A: P { } // dynamically, Int does conform to A.P!</div><div class=""><br class=""></div><div class="">Swift’s model is that the selection among ad hoc overloads is performed statically based on local knowledge, and is consistent across all “specializations” of a generic function. Protocol requirements and overridable methods are the customization points.</div><div class=""><br class=""></div><div class="">Selecting ad hoc overloads at runtime is possible, but of course it has downsides. You could run into run-time ambiguities, for example:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module A</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public protocol P { }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public protocol Q { }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func f<T>(_:T) { print(“unspecialized”) }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func f<T: P>(_: T) { print(“specialized for P”) }</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func f<T: Q>(_: T) { print(“specialized for Q”) }</div></div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public func g<T>(_ x: T) { f(x) }</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module B</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>import A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public extension Int: P { }<span class="Apple-tab-span" style="white-space: pre;">        </span></div><div class=""><br class=""></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module C</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>import A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>public extension Int: Q { }<span class="Apple-tab-span" style="white-space: pre;">        </span></div></div><div class=""><br class=""></div></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>// Module C</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>import A</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>func testG(x: Int) {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span> g(x) // run-time ambiguity: which specialized “f” do we get?</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">There are reasonable answers here if we know what the potential set of overloads is at compile-time. It’s a problem I’ve been interested in for a <a href="https://parasol.tamu.edu/~jarvi/papers/pldi06.pdf" class="">long time</a>. That dynamic dispatch can be implemented somewhat reasonably (the compiler can emit a static decision tree so long as we’re willing to limit the set of overloads to the ones that are visible from g(_:), and can be folded away by the optimizer when we’re specializing the function and the visibility of the types and/or protocols in question is limited.</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">As far as changes to Swift, `@_specialize` already does exactly this (except it is treated as a hint). You would need to transform the function to something like <function-name>_<mangled-type-name>(…) and a table of transformed functions, but after that you can just treat the functions as normal functions (and ignore the fact they were defined as generic). So, yes, specializations should be forced at every level. While this will lead to some code bloat, since it only occurs for the functions marked by the user, I would imagine it’s: (a) limited to the extent it occurs; and (b) manageable by simply not using the attribute (and using protocol witness tables instead). But at least that way you give the user the choice to do what is best for the particular situation.</div></div></div></blockquote><div class=""><br class=""></div>For reference, `@_specialize` is doing dynamic dispatch. That dynamic dispatch gets optimized away when we specialize the generic function, the same way I mentioned about.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: 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-caps: 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="">There might be a reasonable solution to the problem you’re encountering. I don’t think it’s “force specialization at compile time like C++”, but something akin to grouping together multiple overloads where we want dynamic dispatch of callers that invoke them, statically diagnosing when that set of overloads can have ambiguities in it (see the paper I referenced above), and teaching the optimizers to resolve that dynamic dispatch statically whenever possible.</div></div></blockquote><br class=""></div><div>Specialization handles casts, so you can handle some cases today by writing the implementation selection logic out:</div><div><br class=""></div><div>func f<T>(x: T) {</div><div> if let i = x as? Int { fooImplForInt(i) }</div><div> else if let f = x as? Float { fooImplForFloat(f) }</div><div> else { fooImplForGeneric(x) }</div><div>}</div><br class=""><div class="">And you'll get the `Int` or `Float` implementation when the specializer optimizes for T == Int or T == Float. This approach has some limitations today, since protocol existentials in particular have limited functionality, and you don't get type refinement of T from the cast. Perhaps we could support testing general type constraints as a form of statement condition, something like this:</div><div class=""><br class=""></div><div class="">func f<T>(x: T) {</div><div class=""> if <T: P> {</div><div class=""> // we can assume T: P here</div><div class=""> x.fooImplFromP()</div><div class=""> } else if <T: Q> {</div><div class=""> // we can assume T: Q here</div><div class=""> x.fooImplFromQ()</div><div class=""> } else {</div><div class=""> fooImplForGeneric(x)</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">I think the fact that one call site maps to one implementation is a feature, and dispatch by control flow is easier to understand than overload resolution. If we want the optimizer to still be able to specialize reliably, the set of overloads that could be dispatched to would likely have to be closed anyway.</div><div class=""><br class=""></div><div class="">-Joe</div></body></html>