<div dir="ltr">I like this approach as a first pass. It leaves room for other, more forgiving strategies later and is relatively easy to explain.</div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jan 24, 2017 at 4:16 PM, David Sweeris via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div><div class="h5"><div><br></div><div>On Jan 24, 2017, at 11:41, Alexis via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div>It’s worth noting that the question of “how do these defaults interact with other defaults” is an issue that has left this feature dead in the water in the Rust language despite being accepted for inclusion two years ago. See <a href="https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496" target="_blank">https://internals.rust-<wbr>lang.org/t/interaction-of-<wbr>user-defined-and-integral-<wbr>fallbacks-with-inference/2496</a> <wbr>for some discussion of the issues at hand.</div><div><br></div><div>For those who don’t want to click that link, or are having trouble translating the syntax/terms to Swift. The heart of Niko’s post is the following (note: functions are used here for expedience; you can imagine these are `inits` for a generic type if you wish):</div><div><br></div><div><div><font face="Courier New">// Example 1: user supplied default is IntegerLiteralConvertible</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">func foo&lt;T=Int64&gt;(t: T) { ... }</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">foo&lt;_&gt;(22)</font></div><div><font face="Courier New">//  ^</font></div><div><font face="Courier New">//  |</font></div><div><font face="Courier New">//  What type gets inferred here?</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">// Example 2: user supplied default isn&#39;t IntegerLiteralConvertible</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">func bar&lt;T=Character&gt;(t: T) { ... }</font></div><div><font face="Courier New"><br></font></div><div><font face="Courier New">bar&lt;_&gt;(22)</font></div><div><font face="Courier New">//  ^</font></div><div><font face="Courier New">//  |</font></div><div><font face="Courier New">//  What type gets inferred here?</font></div></div><div><br></div><div><br></div><div>There are 4 strategies:</div><div><br></div><div>(Note: I use “integer literal” here for simplicity; in general it&#39;s “any kind of literal, and its associated LiteralType”. So this reasoning also applies to FloatLiteralType, StringLiteralType, BooleanLiteralType, etc.)</div><div><div><br></div><div>* Unify all: always unify the variables with all defaults. This is the conservative choice in that it gives an error if there is any doubt.</div><div><br></div><div>* Prefer literal: always prefer IntegerLiteralType (Int). This is the maximally backwards compatible choice, but I think it leads to very surprising outcomes.</div><div><br></div><div>* Prefer user: always the user-defined choice. This is simple from one point of view, but does lead to a potentially counterintuitive result for example 2.</div><div><br></div><div>* Do What I Mean (DWIM): Prefer the user-defined default, except in the case where the variable is unified with an integer literal <i>and</i> the user-defined default isn&#39;t IntegerLiteralConvertible. This is complex to say but leads to sensible results on both examples. (Basically: prefer user, but fallback to IntegerLiteralType if the user default doesn’t actually make sense)</div></div><div><br></div><div><pre style="overflow:auto;font-family:Consolas,Menlo,Monaco,&#39;Lucida Console&#39;,&#39;Liberation Mono&#39;,&#39;DejaVu Sans Mono&#39;,&#39;Bitstream Vera Sans Mono&#39;,&#39;Courier New&#39;,monospace;font-size:14px;color:rgb(34,34,34)"><code style="font-family:Consolas,Menlo,Monaco,&#39;Lucida Console&#39;,&#39;Liberation Mono&#39;,&#39;DejaVu Sans Mono&#39;,&#39;Bitstream Vera Sans Mono&#39;,&#39;Courier New&#39;,monospace;font-size:1em;overflow:auto;background-color:rgb(248,248,248);word-wrap:normal;display:block;padding:5px 10px;max-height:500px">| Strategy       | Example 1 | Example 2 |
| -------------- | --------- | --------- |
| Unify all      | Error     | Error     |
| Prefer literal | Int       | Int       |
| Prefer user    | Int64     | Error     |
| DWIM           | Int64     | Int       |</code></pre></div><div><br></div><div>Personally, I’ve always favoured DWIM. Especially in Swift where IntegerLiteralType inference is so frequently used (you don’t want adding a default to cause code to stop compiling!). In practice I don’t expect there to be many cases where this ambiguity actually kicks in, as it requires the user-specified default to be a LiteralConvertible type that isn&#39;t the relevant LiteralType, and for the type variable to affect an actual Literal. So &lt;T=String&gt;(x: T) never causes problems, but &lt;T=StaticString&gt;(x: T) does.</div><div><br></div><div>As for the matter of “what if I want the other one” — you clearly know the actual type you want; just name it explicitly.</div></div></blockquote><br></div></div><div>We could just remove that parameter from the type inference system... if the default value is Int and the user passes in a String, that&#39;d be an error, unless the user also sets that parameter to String.</div><div><br></div><div>I&#39;d envisioned using default parameters as more &quot;compile-time configuration options&quot; than something for the type system to actually have deal with. IIRC, I was trying to come up with a way to write just one arbitrary-sized integer struct where I *could* specify the width of its internal calculations, but would usually just use a default value.</div><div><br></div><div>- Dave Sweeris</div></div><br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
<br></blockquote></div><br></div>