<div dir="ltr">That&#39;s a good example Alexis. I do agree that generic arguments are inferred in a lot of cases, my point was that they should not be inferred in &quot;type declarations&quot;. Not sure what&#39;s the right terminology here, but I mean following places:<div><br></div><div>(I) Variable/Constant declaration</div><div><br></div><div>  ```</div><div>  let x: X</div><div>  ```</div><div><br></div><div>(II) Property declaration</div><div><br></div><div>  ```</div><div>  struct T {</div><div>    let x: X</div><div>  }</div><div>  ```</div><div><br></div><div>(III) Function declaration</div><div><br></div><div>  ```</div><div>  func a(x: X) -&gt; X</div><div>  ```</div><div><br></div><div><div>(IV) Enumeration case declaration</div><div><br></div><div>  ```</div><div>  enum E {</div><div>    case x(X)</div><div>  }</div><div>  ```</div></div><div><br></div><div><div>(V) Where clauses</div><div><br></div><div>  ```</div><div>  extensions E where A == X {}  </div><div>  ```</div></div><div><br></div><div>In those cases `X` should always mean `X&lt;Int&gt;` if it was defined as `struct X&lt;T = Int&gt;`. That&#39;s all my rule says. Sorry for not being clear in the last email :)</div><div><br></div><div>As for the other cases, mostly those where an instance is created, inference should be applied.</div><div><br></div><div>Let&#39;s go through your examples. Given</div><div><br></div><div><span style="font-size:12.800000190734863px">struct BigInt: Integer {</span><br style="font-size:12.800000190734863px"><span style="font-size:12.800000190734863px">  var storage: Array&lt;Int&gt; = []</span><br style="font-size:12.800000190734863px"><span style="font-size:12.800000190734863px">}</span><br></div><div><br></div><div><span style="font-size:12.800000190734863px">func process&lt;T: BinaryInteger&gt;(_ input: BigInt&lt;T&gt;) -&gt; BigInt&lt;T&gt; { ... }</span><br style="font-size:12.800000190734863px"></div><div><br></div><div><span style="font-size:12.800000190734863px">what happens with `</span><span style="font-size:12.800000190734863px">let val1 = process(BigInt())`? </span><span style="font-size:12.800000190734863px">I think this is actually the same problem as what happens in case of `let x = BigInt()`.</span></div><div><br></div><div><span style="font-size:12.800000190734863px">In such case my rule does not apply as we don&#39;t have full type declaration. In </span><span style="font-size:12.800000190734863px">`let x = BigInt()` type is not defined at all, while in `</span><span style="font-size:12.800000190734863px">func process&lt;T: BinaryInteger&gt;(_ input: BigInt&lt;T&gt;) -&gt; BigInt&lt;T&gt; { ... }` </span><span style="font-size:12.800000190734863px">type is explicitly weakened or &quot;undefaulted&quot; if you will. </span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">We should introduce new rule for such cases and allowing `Storage=Int` default to participate in such expressions would make sense. As you said, it also solves second example: </span><span style="font-size:12.800000190734863px">let val2 = process(0).</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">I guess this would be the problem we thought we were solving initially and in that case I think the solution should be what Doug suggested: </span><span style="font-size:12.800000190734863px">if you can’t infer a particular type, fill in a default.</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">Of course, if the default conflicts with the generic constraint, it would not be filled in and it would throw an error.</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">For the sake of completeness,</span></div><div><span style="font-size:12.800000190734863px"><br></span></div><div><span style="font-size:12.800000190734863px">func fastProcess(_ input: BigInt&lt;Int64&gt;) -&gt; BigInt&lt;Int64&gt; { ... }</span><br style="font-size:12.800000190734863px"><span style="font-size:12.800000190734863px">let val3 = fastProcess(BigInt())</span><span style="font-size:12.800000190734863px"><br></span></div><div><br></div><div>would certainly infer the type from context as my rule does not apply to initializers. It would infer BigInt&lt;Int64&gt;.</div><div><br></div><div>As for your last example, I guess we can&#39;t do anything about that and that&#39;s ok.</div><div><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 25, 2017 at 7:50 PM, Alexis <span dir="ltr">&lt;<a href="mailto:abeingessner@apple.com" target="_blank">abeingessner@apple.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Yes, I agree with Xiaodi here. I don’t think this particular example is particularly compelling. Especially because it’s not following the full evolution of the APIs and usage, which is critical for understanding how defaults should work.<br>
<br>
<br>
Let&#39;s look at the evolution of an API and its consumers with the example of a BigInt:<br>
<br>
<br>
struct BigInt: Integer {<br>
  var storage: Array&lt;Int&gt; = []<br>
}<br>
<br>
<br>
which a consumer is using like:<br>
<br>
<br>
func process(_ input: BigInt) -&gt; BigInt { ... }<br>
let val1 = process(BigInt())<br>
let val2 = process(0)<br>
<br>
<br>
Ok that&#39;s all fairly straightforward. Now we decide that BigInt should expose its storage type for power-users:<br>
<br>
<br>
struct BigInt&lt;Storage: BinaryInteger = Int&gt;: Integer {<br>
  var storage: Array&lt;Storage&gt; = []<br>
}<br>
<br>
<br>
Let&#39;s make sure our consumer still works:<br>
<br>
<br>
func process(_ input: BigInt) -&gt; BigInt { ... }<br>
let val1 = process(BigInt())<br>
let val2 = process(0)<br>
<br>
<br>
Ok BigInt in process’s definition now means BigInt&lt;Int&gt;, so this still all works fine. Perfect!<br>
<br>
<br>
But then the developer of the process function catches wind of this new power user feature, and wants to support it.<br>
So they too become generic:<br>
<br>
<br>
func process&lt;T: BinaryInteger&gt;(_ input: BigInt&lt;T&gt;) -&gt; BigInt&lt;T&gt; { ... }<br>
<br>
<br>
The usage sites are now more complicated, and whether they should compile is unclear:<br>
<br>
<br>
let val1 = process(BigInt())<br>
let val2 = process(0)<br>
<br>
<br>
For val1 you can take a hard stance with your rule: BigInt() means BigInt&lt;Int&gt;(), and that will work. But for val2 this rule doesn&#39;t work, because no one has written BigInt unqualified. However if you say that the `Storage=Int` default is allowed to participate in this expression, then we can still find the old behaviour by defaulting to it when we discover Storage is ambiguous.<br>
<br>
We can also consider another power-user function:<br>
<br>
<br>
func fastProcess(_ input: BigInt&lt;Int64&gt;) -&gt; BigInt&lt;Int64&gt; { ... }<br>
let val3 = fastProcess(BigInt())<br>
<br>
<br>
Again, we must decide the interpretation of this. If we take the interpretation that BigInt() has an inferred type, then the type checker should discover that BigInt&lt;Int64&gt; is the correct result. If however we take stance that BigInt() means BigInt&lt;Int&gt;(), then we&#39;ll get a type checking error which our users will consider ridiculous: *of course* they wanted a BigInt&lt;Int64&gt; here!<br>
<br>
We do however have the problem that this won’t work:<br>
<br>
<br>
let temp = BigInt()<br>
fastProcess(temp) // ERROR — expected BigInt&lt;Int64&gt;, found BigInt&lt;Int&gt;<br>
<br>
<br>
But that’s just as true for normal ints:<br>
<br>
<br>
let temp = 0<br>
takesAnInt64(temp) // ERROR — expected Int64, found Int<br>
<br>
<br>
Such is the limit of Swift’s inference scheme.<br>
<br>
</blockquote></div><br></div></div>