Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>At a high level, method type inference works like this.</p> <p>First we make a list of all the <em>arguments</em> -- the expressions you supply -- and their corresponding <em>formal parameter type</em>. </p> <p>Let's look at a more interesting example than the one you give. Suppose we have</p> <pre><code>class Person {} class Employee : Person {} ... Person p = whatever; Employee p2 = whatever; </code></pre> <p>and the same call. So we make the correspondences:</p> <pre><code>p --&gt; T1 p2 --&gt; T1 5 --&gt; T2 </code></pre> <p>Then we make a list of what "bounds" are on each type parameter and whether they are "fixed". We have two type parameters, and we start with no upper, lower or exact bounds.</p> <pre><code>T1: (unfixed) upper { } lower { } exact { } T2: (unfixed) upper { } lower { } exact { } </code></pre> <p>(Recall our recent discussion in another question about the relative sizes of types being based on whether or not a type was more or less restrictive; a type that is more restrictive is <em>smaller</em> than one that is less restrictive. Giraffe is smaller than Animal because more things are Animals than are Giraffes. The "upper" and "lower" bound sets are exactly that: the solution to the type inference problem for a given type parameter must be <em>larger than or identical to</em> every lower bound and <em>smaller than or identical to</em> every upper bound, and <em>identical to</em> every exact bound.)</p> <p>Then we look at each argument and its corresponding type. (If the arguments are lambdas then we might have to figure out the <em>order</em> in which we look at arguments, but you don't have any lambdas here so let's ignore that detail.) For each argument we make an <em>inference</em> to the formal parameter type, and add the facts that we deduce about that inference to the bound set. So after looking at the first argument, we deduce the bounds:</p> <pre><code>T1: (unfixed) upper { } lower { Person } exact { } T2: (unfixed) upper { } lower { } exact { } </code></pre> <p>After the second argument we deduce the bounds</p> <pre><code>T1: (unfixed) upper { } lower { Person, Employee } exact { } T2: (unfixed) upper { } lower { } exact { } </code></pre> <p>After the third argument we deduce the bounds:</p> <pre><code>T1: (unfixed) upper { } lower { Person, Employee } exact { } T2: (unfixed) upper { } lower { int } exact { } </code></pre> <p>After we have made as much progress as we can, we "fix" the bounds by finding the <em>best type in the bounds set that satisfies every bound</em>. </p> <p>For T1, there are two types in the bounds set, <code>Person</code> and <code>Employee</code>. Is there one of them that satisfies every bound in the bounds set? Yes. <code>Employee</code> does not satisfy the <code>Person</code> bound because <code>Employee</code> is a smaller type than <code>Person</code>; <code>Person</code> is a <em>lower bound</em> -- it means <em>no type smaller than <code>Person</code> is legal</em>. <code>Person</code> does satisfy all the bounds: <code>Person</code> is identical to <code>Person</code> and is larger than <code>Employee</code>, so it satisfies both bounds. The best type in the bounds set that satisfies every bound is for T1 is <code>Person</code> and for T2 obviously it is <code>int</code> because there is only one type in the bounds set for T2. So we then fix the type parameters:</p> <pre><code>T1: (fixed) Person T2: (fixed) int </code></pre> <p>Then we ask "do we have a fixed bound for every type parameter?" and the answer is "yes", so type inference succeeds.</p> <blockquote> <p>If I change the first argument's type to <code>dynamic</code> then how is T1 inferred?</p> </blockquote> <p>If any argument is dynamic then inference of T1 and T2 is deferred until runtime, at which point the semantic analyzer considers the <em>most derived accessible runtime type</em> of the value as the type for the lower bound supplied by the dynamic argument.</p> <hr> <p>If this subject interest you and you want to learn more, there is a video of me explaining the C# 3 version of the algorithm here: </p> <p><a href="http://blogs.msdn.com/b/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx" rel="noreferrer">http://blogs.msdn.com/b/ericlippert/archive/2006/11/17/a-face-made-for-email-part-three.aspx</a> </p> <p>(C# 3 did not have upper bounds, only lower and exact bounds; other than that, the algorithms are pretty much the same.)</p> <p>A number of articles I've written about type inference problems are here:</p> <p><a href="http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/" rel="noreferrer">http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload