Software Testing Blog

C# Method Type Inference with Multiple Interface Implementations

Today in ATBG, we have a question from “Eric L”, who says that though he is a long-time writer of a blog about C#, he still sometimes gets confused about the semantics of language features that he helped design, implemented several times, and uses every day. Apparently C# is a complicated language! So Eric, what’s your question?

Thanks for taking my question, bug guys. Consider the following program, which is a greatly distilled version of a far more complicated program:

class Alpha { }
class Bravo { }
interface ICharlie<in T> { }
class Delta :
  ICharlie<Alpha>,
  ICharlie<Bravo>
{
  static void Echo<U>(ICharlie<U> icu, U u)
  { }
  static void Main()
  {
    Echo(new Delta(), new Alpha());
  }
}

Method type inference here infers that I meant to say Echo, which certainly seems plausibly correct. But I am concerned. It appears to be ambiguous whether Delta is to be converted to ICharlie<Alpha> or ICharlie<Bravo>. I expected this to fail with an “unable to infer” error. I seem to recall that you added a line to the spec in C# 4 calling out that the type must be unique for inference to succeed. My question is: shouldn’t type inference fail here?

Well Eric, that is an excellent question.

The specification would appear to agree with you; in section 7.5.2.9 it says that the requirement is:

[the formal parameter type] is […] interface […] IC<V1…Vk> and there is a unique type IC<U1…Uk> such that [the argument type] […] implements IC<U1…Uk>.

This line of the spec is a bit confusing even with all the parentheticals elided, which is why I added a special clarifying line immediately following:

The “uniqueness” restriction means that in the case

interface IC<T>{}
class D: IC<A>, IC<B>{}

then no inference is made when inferring from D to IC<T> because [the type argument] could be A or B.

Notice the key point here: if a unique construction of the generic interface cannot be found, then the consequence is that no inference is made from this argument, not that type inference fails. Type inference abandons this argument and moves on to the next argument, from which it deduces that U has a lower bound of Alpha. Since that is the only bound deduced for the only generic type parameter, that’s the type argument chosen for the parameter. That gives us the applicable method call:

Echo<Alpha>(new Delta(), new Alpha());

which clearly would be perfectly legal, so the program compiles and runs cleanly. In the similar case where there is no second argument then indeed this would produce a type inference failure error because no inferences at all would be made from the sole argument.

– Eric

  1. I have to admit that I thought this was a trick question. I looked at it, thought that due to the second parameter there was only one way to interpret it and thus if it was coming up here that must not actually be the case.

    It seems like one of those cases where too much knowledge is a bad thing. 😉

  2. The nicest duffel bags are those made from leather material. Leather-based often arrives in three several assorted colors to match your personal perception of design. As being a traveling bag, it is superior to possess a leather duffel bag considering that you can easily use it for a official or even a informal placing.

Leave a Reply

Your email address will not be published. Required fields are marked *