<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br></div><div>On Jan 24, 2017, at 11:41, Alexis via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><div class="">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&nbsp;<a href="https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496" class="">https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496</a>&nbsp;for some discussion of the issues at hand.</div><div class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class=""><div class=""><font face="Courier New" class="">// Example 1: user supplied default is IntegerLiteralConvertible</font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">func foo&lt;T=Int64&gt;(t: T) { ... }</font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">foo&lt;_&gt;(22)</font></div><div class=""><font face="Courier New" class="">// &nbsp;^</font></div><div class=""><font face="Courier New" class="">// &nbsp;|</font></div><div class=""><font face="Courier New" class="">// &nbsp;What type gets inferred here?</font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">// Example 2: user supplied default isn't IntegerLiteralConvertible</font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">func bar&lt;T=Character&gt;(t: T) { ... }</font></div><div class=""><font face="Courier New" class=""><br class=""></font></div><div class=""><font face="Courier New" class="">bar&lt;_&gt;(22)</font></div><div class=""><font face="Courier New" class="">// &nbsp;^</font></div><div class=""><font face="Courier New" class="">// &nbsp;|</font></div><div class=""><font face="Courier New" class="">// &nbsp;What type gets inferred here?</font></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">There are 4 strategies:</div><div class=""><br class=""></div><div class="">(Note: I use “integer literal” here for simplicity; in general it's “any kind of literal, and its associated LiteralType”. So this reasoning also applies to FloatLiteralType, StringLiteralType, BooleanLiteralType, etc.)</div><div class=""><div class=""><br class=""></div><div class="">* 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 class=""><br class=""></div><div class="">* Prefer literal: always prefer IntegerLiteralType (Int). This is the maximally backwards compatible choice, but I think it leads to very surprising outcomes.</div><div class=""><br class=""></div><div class="">* 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 class=""><br class=""></div><div class="">* Do What I Mean (DWIM): Prefer the user-defined default, except in the case where the variable is unified with an integer literal <i class="">and</i> the user-defined default isn'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 class=""><br class=""></div><div class=""><pre style="overflow: auto; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace; font-size: 14px; color: rgb(34, 34, 34);" class=""><code style="font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace; font-size: 1em; overflow: auto; tab-size: 4; background-color: rgb(248, 248, 248); word-wrap: normal; display: block; padding: 5px 10px; max-height: 500px;" class="">| Strategy       | Example 1 | Example 2 |
| -------------- | --------- | --------- |
| Unify all      | Error     | Error     |
| Prefer literal | Int       | Int       |
| Prefer user    | Int64     | Error     |
| DWIM           | Int64     | Int       |</code></pre></div><div class=""><br class=""></div><div class="">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'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 class=""><br class=""></div><div class="">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>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'd be an error, unless the user also sets that parameter to String.</div><div><br></div><div>I'd envisioned using default parameters as more "compile-time configuration options" 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></body></html>