<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><span></span></div><div><div><div id="AppleMailSignature">Oh, I see. &nbsp;The constraint solver is picking an overload that better matches the caller rather than the callee's type, which differs from C++ because the template expansion process considers specific-type overloads more specific. &nbsp;We don't consider less-generic prototypes than the caller here because we aren't performing a (major) syntactic transformation in the process of solving a system of type variables. &nbsp; In order to change the language to adopt this feature, Sema would have to have knowledge of the candidate set of specializations, either user-specified or SILOptimizer-generated, beforehand. &nbsp;It's not impossible to imagine, but it does create an interesting backdependency on future potential optimizations, and would potentially majorly change the behavior of a Debug or Release build (unless specialization were forced at all optimization levels).</div><div id="AppleMailSignature"><br></div></div><div id="AppleMailSignature">~Robert Widmann</div><div><br>2017/02/05 12:37、Abe Schneider &lt;<a href="mailto:abe.schneider@gmail.com">abe.schneider@gmail.com</a>&gt; のメッセージ:<br><br></div><blockquote type="cite"><div>Hi Robert,<br class=""><br class="">Sorry, I’m not sure I understand your question. In c++ you can do the following:<br class=""><br class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">struct Storage {};</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">struct CBlasStorage: Storage {};</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class="">template &lt;typename S&gt;&nbsp;class Tensor {};</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class="">template &lt;typename S&gt;<br class="">Tensor&lt;S&gt; dot(const Tensor&lt;S&gt; &amp;lhs, const Tensor&lt;S&gt; &amp;rhs) {<br class="">&nbsp; std::cout &lt;&lt; "general version called" &lt;&lt; std::endl;<br class="">&nbsp; Tensor&lt;S&gt; result;<br class="">&nbsp; return result;<br class="">}</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class=""></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class="">// specialized version for CBlasStorage<br class="">template &lt;&gt;<br class="">Tensor&lt;CBlasStorage&gt; dot(const Tensor&lt;CBlasStorage&gt; &amp;lhs, const Tensor&lt;CBlasStorage&gt; &amp;rhs) {<br class="">&nbsp; std::cout &lt;&lt; "specialized version called" &lt;&lt; std::endl;<br class="">&nbsp; Tensor&lt;CBlasStorage&gt; result;<br class="">&nbsp; return result;<br class="">}</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class="">// this preserves type information and will call the appropriate `dot`<br class="">template &lt;typename T&gt;<br class="">void doSomething(const Tensor&lt;T&gt; &amp;lhs, const Tensor&lt;T&gt; &amp;rhs) {<br class="">&nbsp; auto result = dot(lhs, rhs);<br class="">}</blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><br class="">int main(int argc, char **argv) {<br class="">&nbsp; Tensor&lt;CBlasStorage&gt; a, b;<br class="">&nbsp; doSomething(a, b); // we should get "specialized version called"<br class="">}</blockquote><div class=""><br class=""></div><div class=""><br class=""></div>The potential equivalent for Swift could look like:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">@_specialize_all</div><div class="">func dot&lt;S:Storage&gt;(_ lhs:Tensor&lt;S&gt;, _ rhs:Tensor&lt;S&gt;) -&gt; Tensor&lt;S&gt; { … }</div></blockquote><div class=""><br class=""></div>Which would cause the compile to create a version of `dot` per S type that it gets called with. Thus, when `doSomething` is called, it would dispatch to that version of `dot`, allowing the type information to be preserved in the same way it does in c++.<div class=""><br class=""></div><div class="">Abe<br class=""><div class=""><br class=""><blockquote type="cite" class="">On Feb 5, 2017, at 11:35 AM, Robert Widmann &lt;<a href="mailto:devteam.codafi@gmail.com" class="">devteam.codafi@gmail.com</a>&gt; wrote:<br class=""><br class="">I don't understand how this change would cause method dispatch to invoke a different prototype. &nbsp;Specialization in either language&nbsp;mentioned doesn't do that.<br class=""><br class="">~Robert Widmann<br class=""><br class="">2017/02/05 11:28、Abe Schneider via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; のメッセージ:<br class=""><br class=""><blockquote type="cite" class="">Hi all,<br class=""><br class="">The current behavior of generics in Swift causes it lose type information at compile time due to the desire of maintaining a single version&nbsp;of the function. This runs counter to how c++ works, which creates a new copy of a function per type, but preserves information to be&nbsp;preserved. This can cause unexpected behavior from the user’s perspective:<br class=""><br class="">&nbsp; protocol DispatchType {}<br class="">&nbsp; class DispatchType1: DispatchType {}<br class=""><br class="">&nbsp; func doBar&lt;D:DispatchType&gt;(value:D) { &nbsp; &nbsp;<br class="">&nbsp; &nbsp; &nbsp; print(“General function called")<br class="">&nbsp; }<br class=""><br class="">&nbsp; func doBar(value:DispatchType1) {<br class="">&nbsp; &nbsp; &nbsp; print("DispatchType1 called")<br class="">&nbsp; }<br class=""><br class="">&nbsp; func test&lt;D:DispatchType&gt;(value:D) {<br class="">&nbsp; &nbsp; &nbsp; doBar(value: value)<br class="">&nbsp; }<br class=""><br class="">&nbsp; test(value: d1) &nbsp; &nbsp; // “General function called”, but it’s not obvious why<br class=""><br class=""><br class="">The suggested method to get around this issue is to use a protocol to create a witness table, allowing for runtime dispatch. However, this&nbsp;approach is not ideal in all cases because: (a) the overhead of runtime dispatch may not be desirable, especially because this is&nbsp;something that can be determined at compile time; and (b) there are some designs in which this behavior can complicate things.<br class=""><br class="">One example of a design where this behavior can be problematic is when a protocol is used to determine what functions get dispatched:<br class=""><br class="">&nbsp; protocol Storage { … }<br class="">&nbsp; class Tensor&lt;S:Storage&gt; { … }<br class=""><br class="">&nbsp; class CBlasStorage: Storage { … }<br class="">&nbsp; class OpenCLStorage: Storage { … }<br class=""><br class="">&nbsp; func dot&lt;S:Storage&gt;(_ lhs:Tensor&lt;S&gt;, _ rhs:Tensor&lt;S&gt;) -&gt; Tensor&lt;S&gt; { … }<br class=""><br class="">&nbsp; // like behavior, these will not work if called from another generic function (but will work for non-generic functions)<br class="">&nbsp; func dot&lt;S:Storage&gt;(_ lhs:Tensor&lt;S&gt;, _ rhs:Tensor&lt;S&gt;) -&gt; Tensor&lt;S&gt; where S:CBlasStorage { … }<br class="">&nbsp; func dot&lt;S:Storage&gt;(_ lhs:Tensor&lt;S&gt;, _ rhs:Tensor&lt;S&gt;) -&gt; Tensor&lt;S&gt; where S:OpenCLStorage { … }<br class=""><br class="">In this case, depending on the underlying storage, we want an optimized version of `dot` to be called. To make this work correctly we can&nbsp;add static methods to `Tensor`, but this has several drawbacks: (a) it makes the `Tensor` class monolithic, every possible method must&nbsp;be determine a priori and be defined in the class; (b) it doesn’t allow new methods to be added Tensor without touching the main class;&nbsp;and (c) it unnecessarily forces users to user the more verbose `Tensor.dot(a, b)`.<br class=""><br class="">Point (a) in theory could be made better by creating a `TensorOps` protocols. However, because type constraints cannot currently be&nbsp;placed on extensions, it is not currently possible to implement.<br class=""><br class=""><br class="">One potential solution would be to add/extend an attribute for generic functions that would force multiple versions of that function to be&nbsp;created. There is already there is a `@_specialize` attribute, but you have to: (a) manually write out all the cases you want to cover; and&nbsp;(b) only affects the compiled code, which does not change this behavior. Due to the fact that `@_specialize` exists, I’m going to assume it&nbsp;wouldn’t be a major change to the language to extend the behavior to compile-time dispatch.<br class=""><br class=""><br class="">Thanks!<br class="">Abe<br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></blockquote></blockquote><br class=""></div></div></div></blockquote></div></body></html>