<div>As I replied above, this doesn't work IMO because omitted generic arguments are inferred, and that can't change without being hugely source-breaking.</div><div><br></div><div>I think it's absolutely essential that adding a default to my library doesn't change the behavior of code that uses my library. That's currently the case, afaict, for all default arguments, and so I think it's essential here.</div><div><br></div><div><br><div class="gmail_quote"><div>On Tue, Jan 24, 2017 at 17:26 Srđan Rašić via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_msg">We are probably taking the wrong direction here and trying to solve the problem that does not need solving. We are discussing how to infer gereneric arguments in type declarations while we should not do that at all. </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Let me repeat Doug's examples:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>struct X<T = Int> { }</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>func f1() -> X<Double> { return X() }</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>func f2() -> X<Int> { return X() }</div><div class="gmail_msg"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>func f2() -> X<Double> { return X() }</div></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>func f3<T>(_: T) -> X<T> { return X() }</div><div class="gmail_msg"><br class="gmail_msg"></div></div><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x1: X = f1() // okay: x1 has type X<Double>?</div><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x2: X = f2() // ambiguous?</div><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x3a: X = f3(1.5) // okay: x3a has type X<Double>?</div></div><div class="gmail_msg"><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x3b: X = f3(1) // okay: x3a has type X<Int>?</div><div class="gmail_msg"><br class="gmail_msg"></div></div></div><div class="gmail_msg"><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><div class="gmail_msg">Thinking about what the generic argument of X should be inferred to for x1, x2 and x3 is pointless. If one omits generic arguments in the variable declaration, one is accepting the defaults. In other words, doing let x: X = ... should always be treated as doing let x: X<Int> = ..., regardless of what we have on the right hand side. No inference should happen in this case. It would mean inferring already specified type. </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Why? Consider what happens if we define x as a property:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">struct Test {</div><div class="gmail_msg"> let x: X</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"> init() {</div><div class="gmail_msg"> x = f()</div><div class="gmail_msg"> }</div><div class="gmail_msg">} </div></div></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">It would make no sense that the initialization in the initializer specializes the generic argument of the property, so for the sake of consistency we should not do it for the variables/constants either. </div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">Given that, we can solve Doug's example as:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x1: X = f1() // error: cannot assign X<Double> to X<Int></div><div class="gmail_msg"><br class="gmail_msg"></div><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x2: X = f2() // ok: using X<Int> overload</div><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x3a: X = f3(1.5) // error like in x1 </div><div class="gmail_msg" style="color:rgb(49,49,49);word-spacing:1px"><div class="gmail_msg"><span class="m_6708874295454453552m_-3834110406811266196Apple-tab-span gmail_msg" style="white-space:pre-wrap">        </span>let x3b: X = f3(1) // ok because rhs is inferred as X<Int></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">I think this is the only valid way to go and it really simplifies things, both the understanding of how the feature works, but also the implementation. </div></div></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">What do you think?</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><br class="gmail_msg"><div class="gmail_quote gmail_msg"><div class="gmail_msg">tir. 24. jan. 2017 kl. 22.16 skrev David Sweeris <<a href="mailto:davesweeris@mac.com" class="gmail_msg" target="_blank">davesweeris@mac.com</a>>:<br class="gmail_msg"></div><blockquote class="gmail_quote gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">On Jan 24, 2017, at 11:41, Alexis via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a>> wrote:<br class="gmail_msg"><br class="gmail_msg"></div><blockquote type="cite" class="gmail_msg"><div class="gmail_msg"><div class="gmail_msg">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" class="gmail_msg" target="_blank">https://internals.rust-lang.org/t/interaction-of-user-defined-and-integral-fallbacks-with-inference/2496</a> for some discussion of the issues at hand.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// Example 1: user supplied default is IntegerLiteralConvertible</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">func foo<T=Int64>(t: T) { ... }</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">foo<_>(22)</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// ^</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// |</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// What type gets inferred here?</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// Example 2: user supplied default isn't IntegerLiteralConvertible</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">func bar<T=Character>(t: T) { ... }</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg"><br class="gmail_msg"></font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">bar<_>(22)</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// ^</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// |</font></div><div class="gmail_msg"><font face="Courier New" class="gmail_msg">// What type gets inferred here?</font></div></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">There are 4 strategies:</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">(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="gmail_msg"><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">* 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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">* 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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">* 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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">* 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="gmail_msg">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="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg"><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="gmail_msg"><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;background-color:rgb(248,248,248);word-wrap:normal;display:block;padding:5px 10px;max-height:500px" class="gmail_msg">| Strategy | Example 1 | Example 2 |<br class="gmail_msg"><br class="gmail_msg">| -------------- | --------- | --------- |<br class="gmail_msg"><br class="gmail_msg">| Unify all | Error | Error |<br class="gmail_msg"><br class="gmail_msg">| Prefer literal | Int | Int |<br class="gmail_msg"><br class="gmail_msg">| Prefer user | Int64 | Error |<br class="gmail_msg"><br class="gmail_msg">| DWIM | Int64 | Int |</code></pre></div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">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 <T=String>(x: T) never causes problems, but <T=StaticString>(x: T) does.</div><div class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">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 class="gmail_msg"></div><div class="gmail_msg"><div class="gmail_msg">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 class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">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 class="gmail_msg"><br class="gmail_msg"></div><div class="gmail_msg">- Dave Sweeris</div></div></blockquote></div></div>
_______________________________________________<br class="gmail_msg">
swift-evolution mailing list<br class="gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="gmail_msg">
</blockquote></div></div>