Constraints are not part of the signature


What happens here?

class Animal { }
class Mammal : Animal { }
class Giraffe : Mammal { }
class Reptile : Animal { }

static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main()
{
    Foo(new Giraffe());
}

Most people assume that overload resolution will choose the second overload. In fact, this program produces a compile error saying that T cannot be Giraffe. Is this a compiler bug?

No, this behaviour is correct according to the spec. First we attempt to determine the candidate set. Clearly the second overload is a member of the candidate set. The first overload is a member of the candidate set if type inference succeeds.

The method type inference algorithm considers only whether the method type arguments can be consistently inferred from the types of the arguments. Method type inference cares not a bit about whether the resulting method is malformed in some other way. Its only job is to work out the best possible type arguments given the arguments to the method. Clearly the best type for T is Giraffe, so that’s what we infer.

So we now have two methods in the candidate set, Foo<Giraffe>, and the second overload. Which is better?

Again, overload resolution looks only at the arguments you passed in, and compares them to the types of all the candidates. The argument is of type Giraffe. We have a choice: argument of type Giraffe goes to parameter of type Giraffe, or argument of type Giraffe goes to parameter of type Animal. Clearly the former is better; it’s an exact match.

Therefore we discard the second overload because it is worse than another candidate. That leaves one candidate left, which is an exact match. Only then, after overload resolution, do we check to see whether the generic constraints are violated.

When I try to explain this to people, they often bring up this portion of the specification as evidence that I am wrong, wrong, wrong:


If F is generic and M has no type argument list, F is a candidate when:
1) type inference succeeds, and
2) once the inferred type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints, and the parameter list of F is applicable with respect to A. [emphasis added]

This appears at first glance to say that Foo<Giraffe> cannot be a candidate because the constraints are not satisfied. That is a misreading of the specification; the bit “in the parameter list” is referring to the formal parameter list, not the type parameter list.

Let me give you an example of where this rule comes into play, so that it’s clear. Suppose we have

class C<T> where T : Mammal {}

static void Bar<T>(T t, C<T> c) where T : Mammal {}
static void Bar(Animal animal, string s) { }

Bar(new Iguana(), null);

Type inference infers that Bar<Iguana> might be a candidate. But that would mean that we are calling a method that converts null to C<Iguana>, which violates the constraint in the declaration of C<T>. Therefore the results of type inference are discarded, and Bar<Iguana> is not added to the candidate set.

So if that’s not the relevant bit of the spec, what is? The relevant bit happens after the best method has been determined, not before.


If the best method is a generic method, the type arguments (supplied or inferred) are checked against the constraints declared on the generic method. If any type argument does not satisfy the corresponding constraints on the type parameter, a compile-time error occurs.

It is often surprising to people that an invalid method can be chosen as the best method, chosen over a less good method that would be valid. (*) The principle here is overload resolution (and method type inference) find the best possible match between a list of arguments and each candidate method’s list of formal parameters. That is, they look at the signature of the candidate method. If the best possible match between the arguments and the signature of the method identify a method that is for whatever reason not possible to call, then you need to choose your arguments more carefully so that the bad thing is no longer the best match. We figure that you want to be told that there’s a problem, rather than silently falling back to a less-good choice.

UPDATE: My Twilight-reading friend Jen from a couple episodes back points out that this is not just good language design, it’s good dating advice. If the best possible match between your criteria and an available guy on Match.com identifies a guy who, for whatever reason, is impossible to call, then you need to choose your criteria more carefully so that the bad guy is no longer the best match.  Words to live by.


(*) I already discussed the related situation of how it is the case that we can choose a static method over an instance method even when there’s no hope of the static method being the right one.

Comments (122)

  1. Jonathan says:

    It seems to me that this is indeed a compiler bug, and what you have shown is that it results from a bug in the spec.

    No, a bug in the compiler would be an implementation that doesn’t match the spec. A bug in the spec is a spec which doesn’t match the desires of the language designers. In this case the implementation, the spec, and the language designers all agree. Now, you might be of the opinion that this was a lousy design decision, but it is not an error. — Eric 

    What is gained by discarding constraint information when finding the best overload?

    The constraint information is not discarded; it’s never even considered in the first place.

    What is gained is the resulting error analysis: if the best applicable match from argument types to formal parameter types produces an error then you probably have an error in your program. We assume that you intended the compiler to choose the best applicable match; if doing so violates a constraint, then we assume you want to be told about that. We don’t say “well, the choice with the best match is A, but since that’s not going to work out, let’s silently choose B and not tell anyone about it.”

    C# tries to not be a “hide your errors and muddle on through” sort of language.

    — Eric

  2. Anthony P says:

    This method of overload resolution prevents us from doing something like this

           static void Foo<T>(T t) where T : Reptile { }
           static void Foo<T>(T t) where T : Mammal { }

    I can’t think of anytime I would necessarily want to do it, perhaps there’s something involving the cold-blooded nature of reptiles that you couldn’t possibly achieve in a less-constrained generic method, but you’re prevented nonetheless. You get “Type blah already defines a member called ‘Foo’ with the same parameter types.”

    This is a consequence of the title of the post: neither the CLR nor C# considers constraints to be part of the signature of a method. Methods of the same name must differ in signature. — Eric

  3. Skynynrd says:

    @Jonathan

    I do not see this as a bug at all. If you cannot overload a method through constraints then it only stands to reason that the compiler should ignore them when performing overload resolution. Any other behavior would be unexpected and not intuitive.

    An analog case of what you are asking the compiler to do is to perform overload resolution based on return types when you cannot overload methods that way:

      static Reptile Foo(Reptile  reptile) {…}

      static Mammal Foo(Mammal mammal) {…}

      …

      Mammal m = Foo(null); //Compile time error. Ambiguous call

    Which is the best match? Well logically it would seem Foo(Mammal mammal) should be the choice because it returns Mammal but due to the fact that overload resolution doesn’t consider return types we get a compile time error.

    Is this a bug? No, the compiler is doing what it should do.

    The golden rule in my opinion should always be that if the compiler has to “guess” in anyway what the code is trying to do then it is better to throw a compile time error than to guess wrong.

  4. Jonathan Allen says:

    Sounds like this is a defect in the C# specification. In Visual Basic it honors constraints for the purpose of overload resolution and this compiles just fine.

    No, this is not a defect in either the specification or the design of the language. This is a deliberate design choice in accordance with the long-standing principles of the design of the C# language. To do it the other way would be a defect.

    Reasoning about C# design choices by pointing out that VB does it differently is not compelling. The VB language designers are building a different language and are making different design choices, in accordance with the design principles for their language. C# has always been a “complain loudly if something looks potentially incorrect” language, and VB has always been a “do your best to figure out what the user meant even if it means sometimes guessing wrong” language. Both philosophies are sensible and useful, and we offer you the choice.

    For example, VB allows overload resolution to succeed when you pass an expression of type Giraffe to a method that requires a parameter of type Mammal, silently inserts a typecast, and crashes at runtime if that turns out to be a bad choice. Is it your contention that this is also a sensible rule for C#, just because it is a sensible rule for VB?

    — Eric

  5. INTPnerd says:

    So much technicality, so little discernment. The code at the beginning of this blog entry should be the only evidence required to show that the the compiler should be changed, whether or not the spec would need to be changed first. And by the way, if Match.com determined that the best match for me was someone who is not even available on Match.com, I would hope that this would not cause the website to display an error message.

    I’m not sure how many more ways I can come up with to explain this. The correct behaviour here is to give an error. The best possible choice is not viable; the correct behaviour is to tell you that, rather than blithely choose the second-best choice and hope for the best. — Eric

  6. > The golden rule in my opinion should always be that if the compiler has to “guess” in anyway what the code is trying to do then it is better to throw a compile time error than to guess wrong.

    Where is the guessing? There is only one viable overload at the call site, the generic version shouldn’t be considered at all.

    The generic version is the best possible choice, and still, it doesn’t work. You don’t think that’s a sensible candidate for an error message? — Eric

    > An analog case of what you are asking the compiler to do is to perform overload resolution based on return types when you cannot overload methods that way:

    That is not the same thing because both Foo(Reptile) and Foo(Mammal) are viable canidates for the parameter null.  In the first example, there is only one viable canidate for Foo(Giraffe).

    As further proof, it returns an “ambiguous call” error not a a generic type parameter error.

  7. INTPnerd says:

    Also a Giraffe is not a Reptile, end of story!

  8. > The generic version is the best possible choice, and still, it doesn’t work. You don’t think that’s a sensible candidate for an error message? — Eric

    What would we lose by considering the type constraints for the purpose of choosing which choice is best?

    I would think that the answer is obvious. When you make an error case into a legal case then you lose the ability to detect the error. (I am for some reason reminded of all those US congresspeople who, over the years implemented much “deregulation” and yet seemed to not realize that “deregulation” simply means “taking acts that used to be crimes against the American people and making them legal”. As the worldwide financial crisis has shown, perhaps some of those acts ought to have remained crimes.) — Eric

    If this is like the ambiguous case caused by the Color Color problem, show us an example.

     

  9. INTPnerd says:

    The compiler would not be guessing at what I want, nor would it be settling for the second best anything. Just think about the inheritance. Here is some simple logic:

    There are two methods called Foo.

    No, there is one non-generic method called foo, and there is a pattern for generating infinitely many additional methods called Foo, the pattern is called Foo<T>. — Eric

    I am calling a method called Foo.

    One of those methods expects a Reptile.

    No, not at all. One of the infinitely many additional methods called foo expects a Reptile. One of them expects a Giraffe. One of them expects an int. One of them expects any (non-pointer, non-void) type you care to name. — Eric

    The other expects an Animal.

    I am passing a Giraffe.

    A Giraffe is never a Reptile.

    A Giraffe is always an Animal.

    It should call the method that accepts what I am passing, a Giraffe, which is an Animal.

    No, it should tell you that you are attempting to call the one that takes a Giraffe, and that it is not legal to do so. — Eric

    I should not have to do anything special to make it clear which method I intend to call, because there is only one method that I could be calling. If you get too far into the technicalities of the specification and how generic parameters work, you will lose perspective. The correct perspective can be gained by looking at the code at the beginning of this blog entry. It is good to think of things from the perspective of the user, which in this case is a C# programmer.

    I am. We hear over and over from our users that the desired behaviour of the language is to inform the developer when the code is wrong, rather than making the guess “Oh, I suppose the developer actually didn’t mean me to call the exact match, they must have meant to call something else.” When faced with incorrect code, we do not make an attempt to guess what it is that you actually meant, we tell you that the code is incorrect. — Eric

    I agree that whenever compiler has to guess at what I want, it should display an error, but there is no guessing here just because the two methods are similar. This is just treating the programmer like they don’t know what they are doing. Should VS also display message prompts asking if I am sure that I want to call Foo and list all methods with a name that is spelled similarly?

    I’m not following your line of argument here. I would think that the more germane analogy is that you want to call RetrieveRecord(), and you type in RetreiveRecord() by mistake. We do not then say “well, the developer probably meant RetrieveRecord, let’s call that instead.” We tell you that there’s a mistake and let you figure out how to fix it. That is treating the programmer like they know what they’re doing. When the compiler makes assumptions about what you meant in the face of an error, that is when the language treats you like it knows better than you do what you meant. — Eric

    If I told Match.com that I wanted to date a Giraffe, it better not show an error message saying that a Giraffe is really similar to a Reptile because they are both Animals, and I need to explicitly specify that I don’t want do date a Reptile before it will select a Giraffe for me.

    That was just a silly joke. It’s not intended to actually be an analogy of the overload resolution process. — Eric

  10. David Nelson says:

    Although I am normally very much in favor of failing fast and raising an error instead of allowing unintuitive behavior, that argument fails to win me over in this case. Not because I think it is invalid, but because I don’t think that the alternative behavior is in any way unintuitive or indicative of an error. Eric, you have stated (repeatedly) that the reason why the compiler raises an error in this case is that “The generic version is the best possible choice, and still, it doesn’t work.” If that argument holds, then of course an error is preferred. But that argument only holds IF you don’t consider type parameter constraints in your definition of “best possible choice”. The C# spec does not consider them, which accurately reflects the intention of the designers, so this does not qualify as a bug. However, there is no reason that I can see why it shouldn’t consider type parameter constraints. If you show me the first code sample and ask me “Which overload is the best choice for this call site?”, I will immediately reply that the second overload is the best choice. You haven’t presented any evidence that it is better for the compiler to not come to the same conclusion.

    “What would we lose by considering the type constraints for the purpose of choosing which choice is best?

    I would think that the answer is obvious. When you make an error case into a legal case then you lose the ability to detect the error.”

    Again, this only holds if you consider the case to be an error. Jonathan clearly doesn’t consider it an error, nor do I, so it is not surprising that neither of us understand what is to be gained by not considering the type constraints.

    Apparently I am not explaining this very well. Let me try another tack.

    When you write a call site without generic type arguments, and there is a generic method in the method group, what you are saying is “I request the compiler to infer what generic method I might be attempting to call here, and then, if that method turns out to be the best method, to act as though I actually did call that method.” If you typed Foo<Giraffe>(new Giraffe()), you’d quite rightly get an error. When you ask the compiler to work out T for you, the compiler does exactly what you asked. It works out that the best possible value for T is Giraffe, reasoning solely from the arguments that *you* provided and the types provided in the generic version of the method. And if doing so produces a method that has all legal parameter types under construction, then that becomes a candidate, exactly as if you’d typed Foo<Giraffe> explicitly. That method undoubtedly must win, since it is an exact match, and is then discovered to be illegal. You told the compiler to infer what types you meant, it did so, and the result was incorrect. The right behaviour is to say “huh? why’d you ask me to make an inference that you could have known was going to be bogus?” The compiler cannot know what you intended, and rather than guessing, tells you that there’s a problem.

    Is that more convincing? — Eric

     

  11. INTPnerd says:

    Eric,

    You are thinking too much about the technicalities of how generics work under the covers instead of the way that they are used to achieve a goal.

    You said:

    "No, there is one non-generic method called foo, and there is a pattern for generating infinitely many additional methods called Foo, the pattern is called Foo<T>."

    This is technically true, but the way the C# programmer thinks of this is as 2 methods. The whole point of generics is to allow the programmer to program generically, not to generate methods. The fact that it actually generates methods is a technicality as to how it achieves that goal. Generics allow the programmer to think of this example as only 2 methods.

    I think the issue can be simplified by taking generics out of the equation altogether. Look at this code:

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo(Reptile reptile) { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    Clearly, the second method should be called.

    You also said:

    "We hear over and over from our users that the desired behaviour of the language is to inform the developer when the code is wrong, rather than making the guess "Oh, I suppose the developer actually didn’t mean me to call the exact match, they must have meant to call something else.""

    I too desire this from C#. I believe that this is evidence for my case, not against it. From my perspective, considering the first method to be an exact match is a mistake, the second method is a closer match. Instead of requiring the programmer to specify that they meant the second method, they should only have to specify something if they meant the first method, since this is less of a match, at least from my perspective.

  12. Jonathan says:

    What if I did this:

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    class Lizard : Reptile { }

    class Iguana : Lizard { }

    static void Foo(Lizard lizard) { }

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Iguana());

    }

    Intuitively, I would expect that Lizard matches better than Reptile and Animal, so Foo(new Iguana()) would call Foo(Lizard lizard). But what actually happens is Lizard is compared to Iguana, not Reptile, because that is the Type inferred for T, so Foo<T>(T t) is called. The compiler just silently did something I did not expect.

  13. susL says:

    > Most people assume that overload resolution will choose the second overload. In fact, this program produces a compile error saying that T cannot be Giraffe. Is this a compiler bug?

    > I’m not sure how many more ways I can come up with to explain this. The correct behaviour here is to give an error. The best possible choice is not viable; the correct behaviour is to tell you that, rather than blithely choose the second-best choice and hope for the best. — Eric

    This is clearly not a compiler bug, and yes, the best choice here is to give an error. But I think this is a spec "bug", because the "best possible choice" of the spec is not "best possible choice" that most (if not all) users expect.

  14. Anthony P says:

    "Intuitively, I would expect that Lizard matches better than Reptile and Animal, so Foo(new Iguana()) would call Foo(Lizard lizard). But what actually happens is Lizard is compared to Iguana, not Reptile, because that is the Type inferred for T, so Foo<T>(T t) is called. The compiler just silently did something I did not expect."

    I can see the argument on constraints and signatures (but can live with the current rules), but not this argument. You’ve got a generic that by rule matches Iguana exactly versus a method that is merely assignment compatible. Even in a pretend world where constraints matter for overload resolution, the generic is the exact and best fit.

  15. Skynyrd says:

    The people that think the current behavior is wrong are not fully understanding the reasoning behind the C# design team’s decision I think. As far as I understand it, its all about avoiding subtle bugs in which the expected generic method will not be called. All the ones who think this is the wrong behavior is because they are expecting (in this trivial example) that the method overload resolution will pick the non generic method because its the only obvious viable option. That seems reasonable, but in a real world scenario with a much more convoluted code base this might not always be the case and maybe, just maybe, the generic method does seem to be the reasonable and expected choice even if its really not viable. If coders were perfect there wouldn’t be any bugs and we would all be coding happily in C++. Fact is we all make mistakes, so avoiding these kind of subtle traps in a language is the way to go IMHO.

    @Jonathan

    "That is not the same thing because both Foo(Reptile) and Foo(Mammal) are viable canidates for the parameter null.  In the first example, there is only one viable canidate for Foo(Giraffe)."

    I think you missed the point of the analogy. Be it that both are viable or not is not the point. Its about using return types in method overload resolution. The compiler has enough information to infer what method you want to call if the C# design team had decided to use return types as part of method overload resolution mechanism. You don’t consider the fact that it doesn’t a bug. Why? I personally find it the right decision because it can be the origin of a whole array of subtle bugs while the advantages of having that feature in the language are very small.

    On the same line of thought I do not see that having constraints as part of the method overload resolution mechanism is a must have feature or something that really makes one’s life easier. Quite the contrary I see it like a potential well of subtle bugs as I mentioned above. The compile time error is a way to avoid this and the workaround is trivial. If you really want the non generic method to be called then simply match its signature, and cast Giraffe to Animal.

    And last but not least, the argument that the compiler is not trusting the coder or thinking it knows better does not stand. If you follow that line of thought then the following code should be legal:

    void Blah(int n) {…}

    double d;

    Blah(d);

    Its obvious I’m calling Blah(int n) so its obvious I know what I’m doing and therefore the compiler should cast d to int silently under the hood and be done with.

    Sorry if I’m not altogether clear, english is not my native language.

  16. Skynyrd says:

    "Intuitively, I would expect that Lizard matches better than Reptile and Animal, so Foo(new Iguana()) would call Foo(Lizard lizard). But what actually happens is Lizard is compared to Iguana, not Reptile, because that is the Type inferred for T, so Foo<T>(T t) is called. The compiler just silently did something I did not expect."

    The compiler does exactly what it should. Foo<Iguana>(Iguana value) is a perfect match and because constraints are honored (an iguana is a reptile) the code compiles perfectly.

    I dont quite follow your reasoning and where the compiler is doing something you don’t expect.

  17. Dave Sexton says:

    @The naysayers

    The bottom line here is your assumption that the author of Foo(new Giraffe()) wants to be calling Foo(Animal animal), but imagine if he didn’t – imagine he actually intended for the compiler to automatically infer T in Foo<T>(T t) and invoke it with new Giraffe(), because, after all, it appears to him to be a valid overload.  In either case, the compiler is doing the correct thing by reporting an error.

    Maybe the problem is that Eric’s example fits on one screen, so you can readily see the where : Reptile constraint.  In the real world, it’s easy to make a mistake like this.

  18. sweko says:

    What i do not understand here is the why?

    static T Reproduce<T>(T mother, T father) where T : Reptile { }

    static T Reproduce<T>(T mother, T father) where T : Mammal { }

    static Animal Reproduce(Animal mother, Animal father) { }

    Usage scenarios of this set of methods do make sense to me, and a human can (usually) correctly infer the correct overload resolution, so why doesn’t  the language specification allow for this kind of logic?

    IMHO, the type constraints are as much a part in the method signature, as any parameter or return type. Defining them is not just some part of syntax sugar that would ward off bad spirits and runtime errors, but also a mechanism that enables me to use the type parameters as specified in the constraint. The method itself is not compiled by ignoring the constrains and plugging them in later, so (IMHO) the call site should be also aware of any type constraints.

    Of course, there are issues (Reproduce(null, null); Reproduce(new Giraffe(), new Iguana()); Reproduce(new Giraffe(), new Monkey())) which could yield errors and unintended results (Giramonkeys), but those can be also solved by the overload resolution as valid or invalid calls.

  19. Andrey Titov says:

    I have ever think generic constraints are not considered by overloads resolution only for one reason: this requires quite a lot of work to implement it and it is not a vital feature, so it was postponed from initial release of generics enabled version of C#, just like covariance and contravariance.

    I also frustrated that I can’t create generic overloads based on generic constraints.

    I’ll try to explain the way I think about generic constraints, that probably share most people above, whom also wants to change the specification:

    Consider your example:

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    When I read it back I think something like "The second method is obvious – it takes Animal, and the first method takes Reptile, and also this method can use additional information if concrete type of the argument is more specific." So actually these methods in my brain looks like

    static void Foo(Reptile reptile) /*this method will benefit if argument is of more specific type*/ { }

    static void Foo(Animal animal) { }

    So now it is counterintuitive for me why Foo(new Giraffe()) fails and does not pick the second overload.

    I feel many people share this way of thinking with me.

    Yes. This works only in simple (but most common) cases. The real problems starts when there is something like this:

    static void DoSomething<T, U, V>(T t, U u, V v)

    where T : V, IFoo, IComparable<T>

    where U : T

    where V : IBar<U>

    {

    }

    + another five crappy overloads.

    It seems if we will try to define some consistent rules to consider generic constraints in overload resolution, than we may run into situation very similar to in-foof operator ( http://blogs.msdn.com/ericlippert/archive/2009/05/21/in-foof-we-trust-a-dialogue.aspx ): it will works fine in 80% of cases common to real life (that’s what I really wish), that are simple enough, but the rest of corner cases will beat us.

    One obvious example is if we will consider generic constraints, we will be unable to pick right overload in ambiguous case (without changing inferred type) even if specify type parameters explicitly:

    class A : IFoo, IBar {}

    static void Do<T>(T foo) where T : IFoo {}

    static void Do<T>(T foo) where T : IBar {}

    statiс void Main()

    {

       Do(new A());

       Do<A>(new A());

       Do<A>((IFoo)new A());

    }

    Probably we can create convention that the third call will work, it can be achieved by (logically) treating signatures as

    static void Do<T>([BindedToTypeParameter("T")]IFoo foo){}

    static void Do<T>([BindedToTypeParameter("T")]IBar foo){}

    But also multiple generic constraints on same parameter and variance will aggravate complexity. But I still believe it may be possible.

    Anyway I know workaround for this limitation. Assume I want to create overload for some method that distinguish classes and structs. I use strategy pattern and hold concrete implementation in static field of generic class, actually I just do resolution manually:

    class Program

    {

       static void Main(string[] args)

       {

           Do("String");

           Do(42);

       }

       static void Do<T>(T value)

       {

           GenericResolutionHelper<T>.Impl.Do(value);

       }

    }

    internal abstract class GenericResolutionHelper<T>

    {

       public static readonly GenericResolutionHelper<T> Impl =

           (GenericResolutionHelper<T>)

           Activator.CreateInstance(

               GetImplType().MakeGenericType(typeof(T))

            );

       private static Type GetImplType()

       {

           return typeof(T).IsValueType

               ? typeof(StructHelper<>)

               : typeof(ClassHelper<>);

       }

       public abstract void Do(T value);

    }

    internal class ClassHelper<T> : GenericResolutionHelper<T>

       where T : class

    {

       public override void Do(T value)

       {

           if (value == null) throw new ArgumentNullException("value");

           Console.WriteLine("{0} is reference type instance", value);

       }

    }

    internal class StructHelper<T> : GenericResolutionHelper<T>

       where T : struct

    {

       public override void Do(T value)

       {

           Console.WriteLine("{0} is value type instance", value);

       }

    }

    So I can live with current rules and do this hack in rare cases when I have a good reason to do this, at least for methods.

    Another thing about generic constraints that is annoying me much more and cannot be avoided such easily – why delegate and enum can’t be generic constraints just like class and struct are?

  20. Aaron G says:

    So much whining.  I really don’t see the big deal.  If overload resolution isn’t working in your favour for some reason then the solution is simple: don’t overload.  Use a different method name.

    I have to do this all the time when a method is intended to operate on, say, any subset of 3 string parameters, or an optional begin date and optional end date for a filter of some kind.  If I’m really unlucky, a null value already means something special and can’t be used as a replacement for "not specified."  Hell, sometimes my C# code is going to be used for interop of some sort and I have to just remember not to use overloads at all, even though the C# compiler itself has no complaints.

    The implementation matches the spec here and the spec matches the intent.  The intent may be a little hard-assed, but it’s hardly the crime against humanity that people are making it out to be.

  21. Aaron says:

    Honestly this pattern seems like bad code smell regardless:

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    Why would you make Foo<T>(T t) accept any T and then put the restriction on it where T : Reptile { }? Wouldn’t it make more sense to declare the parameter as Reptile since that’s the only thing that can get passed in anyways due to the restriction? I guess my question is what’s the benefit of declaring it as a Generic parameter when you’re going to restrict the input in the where clause.

  22. Grico says:

    This is an academic case anyhow People are moaning about not having constraints taking part in method overload resolution but they are oblivious to the fact that this code isn’t IMO the right thing to do:

    Foo<T>(T t) where T: Blah

    Honestly i understand and use restraints like class, struct or new(). But in this example I would always choose to implement the non generic Foo(Blah t). I really dont see the advantage of using a generic method in this case and much less if the class where its implemented muddles with "similar" non generic methods.

  23. fred says:

    Nice behavior from Refactoring (even manual Refactoring) perspective.

    (If you change Foo<T> constraints, clients will not be affected.)

  24. David Nelson says:

    @Eric,

    "…Is that more convincing?"

    No, it isn’t. You basically just restated the same argument you were already making. The key point of disagreement is this sentence:

    "It works out that the best possible value for T is Giraffe, reasoning solely from the arguments that *you* provided and the types provided in the generic version of the method."

    Yes, that is what it does, in accordance with the spec. What I and others are saying is that is not what it SHOULD do. What it should do is work out the best possible value for T, reasoning from the arguments provided by the call site, the types provided in the generic version of the method, and the constraints declared on those types.

    "That method undoubtedly must win, since it is an exact match, and is then discovered to be illegal."

    If it is illegal, then it is NOT an exact match 🙂 I understand that the compiler’s current behavior is to make a distinction between matching methods and legal methods, but programmers don’t make any such distinction. That is precisely why I would claim that the second overload is the best one simply by looking at it.

    "The right behaviour is to say ‘huh?…"

    No, the right behavior is to do what I asked it to do: find the best overload that can be legally called, and call it.

    Overall, I agree with INTPnerd:

    "You are thinking too much about the technicalities of how generics work under the covers instead of the way that they are used to achieve a goal."

  25. Grico says:

    As a matter of fact, I really don’t see the use of constraints like where: Blah.

    I migh tbe comitting heresy here, but if you are constraining a generic type to a certain class or descendants of said class why dont you implement the non generic option to begin with. What’s the advantage of using generics in that scenario a part from having your code look cooler and impressing your boss?

  26. David Nelson says:

    @Skynyrd,

    "The people that think the current behavior is wrong are not fully understanding the reasoning behind the C# design team’s decision…its all about avoiding subtle bugs…"

    I fully understand that the C# team thinks they are avoiding subtle bugs. Eric already explicitly stated as much: "We figure that you want to be told that there’s a problem, rather than silently falling back to a less-good choice." However, I do not believe in this example that the second overload is "a less-good choice", I believe that it is in fact the best choice, and should be called.

    "…in a real world scenario with a much more convoluted code base this might not always be the case…"

    By all means, show me a case where this rule prevents unintuitive behavior and I will be happy to consider it. I have been trying to think of one since I first read the article, but have so far drawn a blank.

  27. David Nelson says:

    @Dave Sexton,

    "Maybe the problem is that Eric’s example fits on one screen, so you can readily see the where : Reptile constraint.  In the real world, it’s easy to make a mistake like this."

    The compiler does not and should not change its behavior based on how far away from each other the methods are declared. The best overload is the best overload, regardless of whether it is declared in the same file or a completely different library altogether.

  28. Grico says:

    @David Nelson

    "No, the right behavior is to do what I asked it to do: find the best overload that can be legally called, and call it."

    Well thats precisely the whole point of the argument. YOU decide that the best legally called method is the non generic one. That doesnt mean that in all 100% of real life situations that should be the case. Many times maybe the coder is expecting the generic method to be called because he’s handling complicated heirarchies, 100s of classes, thousands of lines of code and not three stupid classes that fit in a paragraph and where everything is crystal clear.

    Under that persepctive what is better? Make a fail safe compiler error or pray that everyone is a perfect coder and will never mistakenly think that the generic method should be called becuase its argument signature matches perfectly? The first just obliges you to do a simple cast and ensures there will never be a bug in the code. The second option satisfies very smart coders like you who see it crystal clear but leaves the door open for less talented coders to introduce a bug in the code because they UNINTENTIONALLY call the non generic method instead (like Skynyrd said, bugs exist. Coders arent perfect so making their life easier is the way to go).

    Besides, like I said before, I’d never implement a generic method like that one to begin with. :p

  29. Eric Lippert says:

    Interesting discussion. The argument for choosing the “worse” method here is, as I understand it, essentially that a candidate method which violates its own constraint ought not to be considered an applicable candidate in the first place. That is, something in addition to well-formedness of the formal parameter types, and convertibility from the arguments to those formal parameter types, ought to be considered as relevant to the question of applicability.

    That argument has the interesting property that it would make calling “Foo<Giraffe>(new Giraffe())” directly into a “there’s no such method” error rather than a “type constraint violated on the best applicable method” error — but we already have lots of heuristics in overload resolution that try to suss out what the user thinks of as “the reason” overload resolution failed. This would just be another such case.

    If this is in fact the argument being advanced then I am surprised that no one has yet focused on the weak part of my argument, a weakness which I call out in the article itself: we DO reject candidates if the deduced formal parameter types are “impossible” types.

    In fact, we do this in two ways. As I showed in the article, we reject candidate methods where the deduced type arguments force the formal parameter types into shapes which violate their own constraints. We also reject candidate methods where the deduced type arguments force the formal parameter types into types which are not accessible at the point of the call. For example:

    public class Program
    {
       public class C : I<C.D>
       {
           private class D {}
       }
       public interface I<T> { }
       public static void M<T>(I<T> t) {}
       public static void M(object d) {}
       static void Main()
       {
           M(new C());
       }
    }

    Here type inference says that M<C.D>(I<C.D>) is a candidate, but we immediately reject it as an inapplicable candidate because C.D is not accessible at the call site. We therefore choose the M(object) overload instead.

    A reasonable counter to my argument is that we are being inconsistent. If it is the case that we consider a method which matches exactly but violates its own constraints to be an “erroneous best match” then it is plausible that we ought to also consider the match on M<C.D>(I<C.D>) to be a better match than the match on M(object), choose it as the best match, and then say “your best possible match leads to an error condition”.

    Incidentally, I was originally in the camp of “methods which violate constraints are not candidates”. In fact, I wanted to go even farther than that — I wanted to not just make these methods not applicable candidates, I wanted to make them not even outputs of type inference. That is, I wanted to design the method type inference algorithm so that type inference would reject inferring formal parameter types that violated any constraint or produced any inaccessible type. But doing so means that the type inference algorithm has to take as its input not just a list of arguments and a list of formal parameters — it has to take in all kinds of extra information about the call context, accessibility rules, and so on.  It is conceptually much cleaner to make type inference reason about only two things: the arguments and the corresponding formal parameters. We should not try to solve all the world’s problems in type inference, but rather, leave all the other analysis to algorithms which care about that other stuff.

    — Eric

  30. INTPnerd says:

    Eric,

    Am I understanding you right that originally, it was designed to work this way to make it easier to implement the compiler?

    Good heavens no. If our goal had been to invent an overload resolution algorithm that was easy to implement, we certainly would have failed badly at that goal. The overload resolution algorithm is extremely complicated and the implementation runs to tens of thousands of lines of nigh-impenetrable code. (Don’t forget, we have to write an implementation that not only implements the spec, but also works while you’re typing code in the IDE, gives sensible error messages, terminates, and so on.) Our goal in writing the overload resolution algorithm is to suss out what the developer meant given the choices we have at hand, and if we cannot figure out unambiguously what the developer meant, to give a sensible diagnostic error. — Eric

    I don’t know anything about the internal implementation of this stuff, so I am probably just revealing how naive I am, but I will throw it out there anyway. I don’t understand why it would be so difficult to implement this to consider type constraints when choosing which method overload is being called. Why not just have it try the generic method first, like it is doing, and then after it realizes that the type constraint is not upheld, look for an alternative method to call, instead of displaying an error message right away? I’m sure it is not as simple as that and this might pollute the elegance of the design of the code, but I just thought I would put it out there.

    It wouldn’t be hard at all. We already have checks to ensure that the deduced formal parameter types satisfy their constraints and involve only accessible types; we could simply add a line of code that also verifies that the method’s constraints are also met. We’d have to fix up the bookkeeping code a bit so that when an error occurs, we give a sensible error message, but that’s easy enough.

    The reason to not implement the proposed feature is because I believe it to be a bad idea to either hide the developer’s bug or assume that we know better than the developer what was intended, not because its hard to do. We don’t want to implement a feature which hides your bugs. — Eric

  31. Konstantin says:

    Eric,

    You are doing the right thing!

    declaring both

    static void Foo<T>(T t) where T : Reptile { }

    and

    static void Foo(Animal animal) { }

    in the same class is clearly bad design. It will lead to hard-to-maintain code.

    I would go one step further and forbid declaring generic and non-generic methods with the same name in a class. Why? Beacuse it should be always clear even for the dumbest software engineer in a team which method will be called.

    Eric, keep your great job in disouraging overengineering-for-a sake-of-looking-supersmart.

  32. David Nelson says:

    @Grico,

    Declaring such a method where Reptile is a generic constraint on a type parameter instead of using it as the type of the parameter directly can be necessary if you plan to use another generic type within the method that does not support contravariance (which is all types prior to C# 4). For example:

    List<T> Foo<T>(T t) where T : Reptile

    {

      var x = new List<T>();

      x.Add(t);

      return x;

    }

    is very different from:

    List<Reptile> Foo(Reptile t)

    {

      var x = new List<Reptile>();

      x.Add(t);

      return x;

    }

  33. David Angers says:

    First let me say I’m not a compiler/language expert, just a developer and I think I could live with things working as they are or the other way around.

    I think the debate at least partly results from two possible ways of looking at constraints.

    Taking static void Foo<T>(T t) where T : Reptile { }

    One could think of this as being a clearer notation for

    static void Foo( T where T : Reptile t)

    {

    }

    which I think is how many developers actually think of it and I think leads to the the desire to have constraints participate in method resolution (I told you only to accept paramteres that match this constraint!)

    On the other hand, one could think of this as being a notation for

    static void Foo( T t)

    {

       where this implementation only works where T : Reptile

    }

    In this case only after the compiler matches the method and then tries to "implement" the method does the "implementation" fail, thus the error.

    "No, not at all. One of the infinitely many additional methods called foo expects a Reptile. One of them expects a Giraffe. One of them expects an int. One of them expects any (non-pointer, non-void) type you care to name. — Eric"

    In this quote I feel you are implicitly using the second "interpretation" by including int as one of the possible methods, whereas in the first approach int isn’t one of the infinite possibilities.

    Very much enjoy your blog,

    Dave

  34. INTPnerd says:

    Eric,

    Thanks for the clarification. I am glad to hear that you do not fall into the "worse is better camp".

    You said

    "I believe it to be a bad idea to either hide the developer’s bug or assume that we know better than the developer what was intended"

    For now I am going to ignore the first part of what you said there about hiding the developer’s bugs and I will focus on the second part about assuming that "we know better than the developer what was intended".

    Here is my main argument for this whole issue. I think that for the example we are discussing, the main problem is that the C# compiler is already making a stupid assumption about what the developer intended. At some point it assumes that the developer intended the generic version even though the calling code makes no references to generics and even though the non generic method is a better match type wise. I agree that the compiler should not change what is specified in the code, but there is nothing about this code to indicate that it is specifying the generic version. All indications are that it is specifying the non-generic version.

    If you consider choosing which overload to call to be an assumption, it certainly chose the least logical of two assumptions. Only after it assumes that the generic method is the one intended does it check if it is callable. At this point since the type constraint is not satisfied, it issues a compiler error. Even if I were to buy into the reasoning, which some have pointed out here, about how in more complex situations it would not be easy for the developer to know which one is called, and therefore should display an error message for that reason, the compiler is displaying an error message for a completely different reason. It thinks it does know which one is being called, the generic one. Even if I were to give in on the issue of whether or not the compiler should be outputting an error message, I would still insist that it should be outputting a completely different error message. One that does not assume it knows which method was intended to be called. It should be something like "Ambiguous call".

    Even with a better error message I still think that it should not be displaying an error message at all. If there is only one method that can be called, and it is not in any way deciding something different from what the code specifies, which in this case it is not, then there is no reason to worry that the developer might have meant something else. Of course, that is possible, but there is always a possibility that the developer meant something else, and we need to test our code to make sure it does what we expect anyway.

    In conclusion, for the code example presented at the outset, it is almost as stupid to assume the programmer meant to call the generic method as it would be to make the same assumption in the following code example(notice the Animal cast):

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo((Animal)new Giraffe());

    }

  35. Anthony P says:

    @INTPnerd

    Essentially, by providing both a non-generic and a generic method in the class, you’re effectively stating "I’m only going to use this non-generic method in a very specific manner with exact matches on the argument type(s)." Assignment compatibility flies out the window. Regardless of the contraint on the generic method, that’s the rule you’re implicitly agreeing to follow.

  36. DRBlaise says:

    I agree with the inconsistencies that @INTPnerd brings up more than the ones Eric brought up.  C# already "assumes it knows better than the developer" when it picks a generic method over the non-generic method.  C# also has rather complicated logic to pick Extension methods using the "closest" first and then the "best".  Again C# assumes it "knows better" instead of a compile time error that would force the developer to make clear the intent of competing Extension methods.  I don’t buy the argument that this particular case is more prone to bugs than the other cases, especially since the constraints are very explicit about when the generic method is valid.  For consistency sake, I think it would be better to use the constraints to determine the best method.

  37. David Nelson says:

    @Eric,

    From a technical perspective, you seem to be understanding my argument. However, you still seem to be missing the perspective of the user. Your argument for why the current behavior of the compiler is the best behavior is circular. You are saying that the compiler should display an error because there is a bug in the code that you don’t want to hide; but it is only a bug because of the way the compiler is already implemented! You are in essence using the spec to justify the spec. If you ignore the current implementation of this behavior, and just look at the code in the first sample from the programmer’s perspective, there is no reason to believe that there is a bug in that code. One Foo should only be called for Reptiles, the other should be called for all Animals. If I call Foo with a Giraffe, I obviously did not intend to call the Foo that is only for Reptiles, so I must have meant to call the other one.

    And there’s the difference of opinion right there. To you it is obvious that the intention was not to call the illegal method. That is not obvious to me at all; coming to that conclusion requires that we accurately model the mental state of developers who have written a program where a perfect match is illegal. It’s hard to say what the intention of such a programmer is. Rather than try to guess, we require that the programmer give us enough information that their intention becomes clear.

    Suppose you write “implicit operator Foo(Bar bar)”. We give you an error that says “FYI conversion operators have to be public and static”. This error models the mental state of the developer: the developer intends to write a user-defined conversion operator, and has done it wrong. In that case, it seems reasonable that our mental model of the developer who wrote a bad program is accurate; the developer did not wish to write, say, a private instance method. This is particularly well justified because many C++ developers who come to C# expect that user-defined operators need not be static; it’s a good idea to inform them explicitly that instance operators are not supported by C#.

    To you it is apparently obvious that the developer meant for the non-generic method to be called. And perhaps in this trivial example it is. But is it the case that in every example where a constraint is violated, the intention was to go to the non-generic version? Remember, it is frequently the case that generic and non-generic versions of a method exist side-by-side because the generic method was added much later, in order to, say, solve a performance problem caused by boxing. Is it unambiguously the right thing to do to drop back down to the old, slow ungeneric version if the generic constraint is accidentally violated? Or is it the right thing to do to tell the developer “it looks like you’re trying to get inference to choose the generic one, but the exact match is illegal”? Obviously I think there’s a case to be made for not making the guess that the developer intended to choose the worse method.  — Eric

    As I stated in my reply to Grico, the differences between the generic and non-generic versions of the first overload are important, but conceptually they are still very similar, and there is no reason for them to be treated differently, just because they are required to be implemented differently for technical reasons.

    “It is conceptually much cleaner to make type inference reason about only two things: the arguments and the corresponding formal parameters.”

    I don’t disagree with this. However, in my opinion the generic constraints are conceptually a part of the formal parameters >from the perspective of the programmer<. Whether they are represented that way in the metadata is not really the point; they look that way when you look at the method declaration.

  38. Pop Catalin says:

    Hi Eric, I also have a few points I’d like to share:

    #1

    I fail to understand why "static void Foo<T>(T t) where T : Reptile" is called best possible match.

    If you expand the generic method using a math formula like Σ1..n = 1 + 2 + 3 + … + n-1 + n, and considering a finite set of static types, you get:

    static void Foo(Reptile t)

    static void Foo(Lizard t)

    static void Foo(Crocodile t)

    static void Foo(Iguana t)

    which is the expanded definition of  "static void Foo<T>(T t) where T  : Reptile"

    Then it is clear that a generic method, is a condensed way of writing a set of methods using a single declaration. And the current method resolution algorithm is a peculiarity.

    The compiler actually expands "static void Foo<T>(T t) where T" to a greater set of methods than the set defined by the method, which in my humble opinion is not mathematically sound. I think generics should behave exactly like the group of non generic methods to which they are equivalent, within a program.

    #2

    We humans are not used to partial evaluations, the compiler does a partial evaluation to find the best match, and chooses an invalid match as the best match, then outputs an error. The assumption is that we as developers always want  the best match to be generic. This is wrong, we want the best match, but not including invalid matches (you know we don’t want invalid matches because you eliminate the largest part of those).

    We as developers "understand constraints" in the way we understand sets and set theory, we don’t assume that any generic method will take any type as a parameter, we know that a constrained generic method takes a subset of types. Interestingly that assumption only exists in the compiler.

    #3

    I’ve never really like this part of the method resolution algorithm, it prevented me from doing static optimizations like the following:

           static int CounElements<T, U>(this T source) where T : IList<U>

           {

               Console.WriteLine("IList");

               return source.Count;

           }

           static int CounElements<T>(this IEnumerable<T> source)

           {

               Console.WriteLine("IEnumerable");

               return source.Count();

           }

           static void Main(string[] args)

           {

               IList<int> newList = new List<int>();

               CounElements(newList);

           }

    I know this is a trivial example, but there were more complex scenarios where I wish I could do this.

  39. Eugene says:

    Not using where restrictions on method just feels inconsistent, because you use restrictions on types, however I think there’s a bigger problem here. It’s the whole overload resolution semantics borrowed from C++ templates.

    C++ templates are just advanced macros — they are factories producing code for given parameters. Template function isn’t a function — only template instance with all parameters specified is. So the only way you can do overload resolution with templates is to find some (C++ only finds 1) template instances and add them to the candidate set.

    C# generics are very different, as you wrote previously (http://blogs.msdn.com/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx). Generic method is a single method that can simply work with multiple types (I’m ignoring value types complications for the sake of simplicity). For the evidence that it’s a single method (I’m talking about semantics, not implementation) consider that overload resolution inside generic is only done once or other calling rules (http://blogs.msdn.com/ericlippert/archive/2007/06/14/calling-static-methods-on-type-variables-is-illegal-part-one.aspx , http://blogs.msdn.com/ericlippert/archive/2007/06/21/calling-static-methods-on-type-variables-is-illegal-part-three.aspx). All of that is the opposite of C++, where there are really multiple methods.

    So with this in mind, it would really make more sense if generics were treated the same as other methods. I.e.

    void Foo<T>(T t);

    void Foo<T>(T t) where T : Bar;

    were exactly the same as

    void Foo(object t);

    void Foo(Bar t);

    rather than being a magic "perfect match". You’d only use generic if you need some constraints across multiple arguments/return type, e.g.

    int Compare<T>(T a, T b);

    void Append<T>(List<T> list, T elem);

    List<T> SingletonList(T elem);

    This automatically gives the intuitive behaviour you argue against in the post 🙂

    Btw, C++ still manages to do what people ask for here — it has SFINAE, that allows to exclude template from overload set based on some conditions. Also, C++ prefers non-template to template when possible — if you had a template but still wrote a special case you probably want this special case to be used.

  40. v.reshetnikov@gmail.com says:

    Eric,

    you stated it yourself that the compiler’s behavior is unexpected for most people. But it is not so bad, because the compiler does not do silently anything unexpected in this case, it issues an explicit error and developers have a chance to modify their code to invoke a method they intend to invoke.

    But let me complicate your code a bit. Let’s say I do not want to invoke Foo directly, I want to pass it as a delegate to another method, Bar. And the method Bar happened to have two overloads:

    using System;

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    class Iguana : Reptile { }

    class P

    {

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Bar(Action<Giraffe> a){}

    static void Bar(Action<Iguana> a){}

    static void Main()

    {

    Bar(Foo);

    }

    }

    The compiler issues two errors:

    error CS0121: The call is ambiguous between the following methods or properties: ‘P.Bar(System.Action<Giraffe>)’ and ‘P.Bar(System.Action<Iguana>)’

    error CS0311: The type ‘Giraffe’ cannot be used as type parameter ‘T’ in the generic type or method ‘P.Foo<T>(T)’. There is no implicit reference conversion from ‘Giraffe’ to ‘Reptile’.

    So far so good. I did not do anything to explicitly specify which overloads of methods Foo and Bar I what to use, so the error remains. Moreover, the additional error for method Bar appears. I can easily fix the errors using explicit casts.

    So, the compiler does not hide my bugs, right? But let us try another example. Suppose I prefer to use lambda syntax to pass the method Foo.

    using System;

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    class Iguana : Reptile { }

    class P

    {

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Bar(Action<Giraffe> a){}

    static void Bar(Action<Iguana> a){}

    static void Main()

    {

    Bar(animal => Foo(animal));

    }

    }

    This code compiles without errors. The compiler reasons as follows: there are 2 overloads of method Bar. But, hey, if I try to use the first, then the parameter ‘animal’ in lambda will be of type Giraffe. But that would lead to the ambiguity in the invocation Foo(animal). So we won’t even treat the first Bar as applicable, and will invoke the second. Now ‘animal’ is Iguana and everything is fine.

    And all this reasoning happens implicitly, without developer’s knowledge. And if the developer made a mistake, it will remain undisclosed. Can you justify the compiler design in this case?

  41. Brian says:

    In contemplating this article, one thing which I did to make this clearer to myself, was asked the question, "What if I, as a developer, *did* want to use the 2nd method in the case that I passed in a Giraffe?" In examining what such an implementation would require, I had a thought:  "Constraints are for preventing code from compiling when you break your own rules, not for deciding what your code will do.  Adding constraints to code should not alter that code’s behavior except in the case that a compiler error is thrown."  Leaving constraints out of the signature makes perfect sense.

  42. While we’re on the subject of type inference, I was wondering why the compiler can’t handle this scenario:

    class Base<T, T2> where T : Base<T, T2> { … }

    class Derived : Base<Derived, D2> { … }

    static void Foo<T, T2>(T t)

     where T : Base<T, T2>;

    Foo(new Derived()); // should infer Foo<Derived, D2>

    And then I realized that it’s actually exactly the same issue as is being discussed in this post. *The constraints are ignored for the purposes of inference*. I encountered this issue about 6 months ago and have been thinking about it ever since and it was only as I started writing this comment to ask about it that I realized what was going on.

    I think the heart of the issue – and why this seems so counterintuitive to so many people, myself included – is precisely the fact that we’re talking about *inference*. The very word itself means "figuring out what was intended". If inference is in play at all, the programmer by definition did NOT specify exactly which method was intended, there’s NOT an "exact" match in some sense, because if it were exact the type parameters would have been spelled out.

    If you’re going to guess (infer) what the programmer intended anyway, why wilfully discard an important part of the information that the programmer supplied? There’s a sort of logic to "we’re not gonna assume he meant us to use that information" but the logical conclusion is "don’t do inference at all", not "assume the opposite, instead, that he intended us to ignore it".

  43. Skynyrd says:

    We are talking about generic type inference here, not coder’s intention inference if I’m not completely lost. In Eric’s example the compiler gives an error because inferring the logical generic type, constraints are not met. So I don’t quite follow your argument here.

    Because inference fails the compiler is not sure if that was what the person who wrote the code wanted and thus stops with a compile time error.

  44. Peter J Fraser says:

    consider (illegal code):

    public T f<T>(T e ) where T: IEnumerable { … }

    public T f<T>(T l ) where T:IList {… }

    As signature for a function to manipulate a list of values,

    where if algorithm is much better if you know indexing exists.

    (The ILinq function Reverse would be an example.)

    Of course the function can be written with one body that

    dynamically selects the best algorithm based on run time code.

  45. Quoting:

    " Bar(new Iguana(), null);

    Type inference infers that Bar<Iguana> might be a candidate. But that would mean that we are calling a method that converts null to C<Iguana>, which violates the constraint in the declaration of C<T>"

    — I don’t understand why it violates the constraint: C<T> is a reference type and null seems to be a a valid value to substitute for an instance of a reference type, why would type inference deem a constraint violation in this case?

  46. David Nelson says:

    @Skynyrd

    "We are talking about generic type inference here, not coder’s intention…"

    The entire reason for type inference to exist is to "guess" (or reason out) the coder’s intention when he has not made it explicit. Otherwise we would just require all generic type parameters to be explicit. So the coder’s intention is very much at the heart of the issue of how far generic type inference should go and what factors it should consider.

    @Abhijeet

    C<T> was declared with the constraint "where T : Mammal". Iguana does not descend from Mammal.

  47. Lord Dust says:

    From INTPnerd : "At some point it assumes that the developer intended the generic version even though the calling code makes no references to generics…"

    Unfortunately, untrue. Don’t forget, the use of type inference is implied with every generic declaration in C#. So, when you write:

    static void Foo<T>(T t)

    you implicitly state "Whenever I make a call to a method named Foo, I MAY be calling this generic method, even if I did not specify a type argument. If you encounter such a call, please use this guide to create the method signature, using the type inference rules if necessary, and put that signature in the candidate list.". In the absence of requiring some piece of syntax to specify "imply a type parameter here", type inference must operate implicitly on every call to a method named Foo. Just not specifying a type parameter is not enough to make it obvious you did not mean to call the generic method.

    From David Nelson : "If I call Foo with a Giraffe, I obviously did not intend to call the Foo that is only for Reptiles, so I must have meant to call the other one."

    Unfortunately, given the way type inference is implied in every call to the named method, also untrue. Let’s assume the compiler does consider the constraint on the generic version. Since the generic version must at least be "constructed" and considered because of the implied use of type inference as specified above, the compiler is left with two choices. The first is a generic method that has the right type argument, but has an argument that violates a constraint. The second is a non-generic method that has an argument that must be cast to be correct. Either way, the programmer has omitted a critical piece of information that would make this situation go away.

    I find it strange that anyone should try to contrast the way the C# compiler handles this with the VB compiler. They both do exactly the same thing: pick one thing that the programmer COULD have written, and act as if this thing HAD, IN FACT, been so written. I would like to think that setting up this situation with such a call at all would be the error, a la "Ambiguous Call" (good idea, INTPnerd). Unfortunately it isn’t; the C# compiler makes an assumption, just like the VB one does. That the C# compiler happens to bump into an error condition afterward is to my mind somewhat incidental. Perhaps a different error message with appropriate documentation would make this all more clear to those who fall into this Pit.

  48. Pop.Catalin says:

    "They both do exactly the same thing: pick one thing that the programmer COULD have written, and act as if this thing HAD, IN FACT, been so written"

    Except there’s and important thing here that I see most people leave out of the equation, The thing that the C# compiler (not the developer) picks is an "invalid method call".  

    The argument here seems to be that the developer would have deliberately chosen an invalid method, the generic one, which I doubt, or that they are unaware that the generic method can’t be chosen because of the constraint, so an error must be issued to warn them. However the following example compiles just fine:

       class Animal { }

       class Mammal : Animal { }

       class Giraffe : Mammal { }

       class Reptile : Animal { }

       static void Foo(Animal animal) { System.Console.WriteLine("Non Generic"); }

       static void Foo<T>(T t) where T : Reptile { System.Console.WriteLine("Generic"); }

       static void Main()

       {

           Foo((Animal)new Reptile());

       }

    and Prints: "Non Generic", because of the exact match between the call and the non generic method. However the cast is reduntant, the developer is forced to insert a cast so that a method that is invalid anyway, won’t be chosen by the compiler (The developer is asked to be explicit, while the alternative is invalid, you usually are asked to be explicit when there is a ambiguous match (between two valid options))

    I can understand that the C# compiler tries to pick generic methods first because they "usually are more specific" and provide a better programming model because of the type flow, however I don’t understand why the compiler considers clearly invalid generic methods in this process.

  49. Lord Dust says:

    “Except there’s and important thing here that I see most people leave out of the equation, The thing that the C# compiler (not the developer) picks is an “invalid method call”.”

    Since the fact that the compiler picks that method is at the heart of this discussion, I believe that that’s probably the only thing that everyone has considered in the equation. I suggest that the part most people disregard is the fact that a Giraffe in the given example ISN’T and Animal.

    As programmers, we model inheritance relationships as an “X is a Y” relationship in order to contrast it with an “X has a Y” composition relationship. We also enjoy the property of inherited classes that the objects they define can be upcast to their superclass with 100% certainty, enabling implicit upcasts at any point necessary. But none of this mitigates the fact that, to the compiler, a Giraffe is NOT an Animal. That cast is not redundant, it’s a requirement. So, to the compiler, unless it transforms that call somehow, *neither* call will actually succeed.

    That the C# compiler should pick a method to that it can’t “fix up” the call enough to succeed is sort of after the fact. It’s making an assumption, no matter what the programmer actually meant to call. I certainly agree that, with the overall intention of the code elided, a call to Foo(Animal animal) is far, far more likely to be what the programmer meant. But that doesn’t mitigate the fact that that’s not what the programmer wrote.

    And I would like to more strongly assert that if the intention was to issue an error because the compiler believes this situation to be ambiguous, the current error is a bizzare way of expressing it.

    There’s no ambiguity error here. If there were, that’s the error the compiler would emit. The method chosen is unambiguous because it is a perfect match. The error is that the method chosen violates its constraints, so that’s the error we give — Eric

  50. Lord Dust says:

    True, although I think the reason for the design principle that led to this situation IS the result of ambiguity on the part of the programmer. Otherwise, why would “we don’t muddle through” have anything to do with it at all? In the face of this particular, it’s become necessary to write an entire blog post explaining why such an error should be emitted. Now that it has become apparent that the intention of the behaviour and error are still unclear, it’s become necessary to write several comments as well.

    “When faced with incorrect code, we do not make an attempt to guess what it is that you actually meant, we tell you that the code is incorrect.”

    This summary of the design principle that drove this situation spells out the reasoning, and I believe that the reasoning is sound and consistent with the design principle. Nearly every explanation for the error emitted by the compiler presented relies on this principle as the reason for the error. And yet, the error message:

    The type ‘Giraffe’ must be convertible to ‘Reptile’ in order to use it as parameter ‘T’ in the generic type or method ‘Foo<T>(T)’

    doesn’t say anything remotely like “We’re faced with a situation where we must guess what you meant, and we’re reporting that we won’t do that.”. Instead, the message says “We’re *guessing that you meant* to call this particular method, and here’s how to call it correctly.”. If the programmer’s intention was to call Foo(Animal animal) (which is the intuitive behaviour for most), this error is supremely uninformative. I would think that throwing AN error, as the language spec states, supports the design principle you mentioned. I would also think that throwing this particular error does not support that same principle.

    The spec says an error must be thrown in this case. I don’t see where the spec states that the error so given must also be determined without considering generic constraints on the method. Were this information taken into consideration whilst issuing an error, it might become more apparent to the user in which way particular bit of code is written incorrectly. This way, the compiler needn’t “muddle on through” anything, nor “guess what it is that you actually meant”; it will still fail on the exact same line for exact same reasons. But should a generic method with implied type parameters fail to validate, try validating everything else in the method group, until and unless one of them should succeed. If one of them is valid, issue something like :

    “An argument in ‘Foo(new Giraffe())’ has caused an implied type parameter to promote a generic method with a violated constraint above other valid method(s). Alter the argument to promote or validate the correct method.”

    I see what you mean. We already do a lot of complicated logic in the overload resolution algorithm to produce meaningful errors; this is another case where we could do better. How we tailor error messages to specific situations using heuristics is a good blog topic for next year. — Eric

  51. David Nelson says:

    "…requires that we accurately model the mental state of developers who have written a program where a perfect match is illegal. It’s hard to say what the intention of such a programmer is.

    is it the right thing to do to tell the developer "it looks like you’re trying to get inference to choose the generic one, but the exact match is illegal"?"

    Once again, you start your argument from the position that "[the] perfect match is illegal." That argument is a non-starter, because my contention from the very beginning has been that the illegal match is NOT the perfect match! It is only hard to say what the intention of the programmer is if you start from the position that what the programmer wrote is ambiguous or illegal. If you instead start from the position that what the programmer wrote is exactly what they intended, the right solution is obvious.

    "…generic and non-generic versions of a method exist side-by-side because the generic method was added much later…

    Is it unambiguously the right thing to do to drop back down to the old, slow ungeneric version if the generic constraint is accidentally violated?"

    Again: the <i>whole point</i> of type inference and overload resolution is for the compiler to determine the right call to make when the programmer has not provided all of the required information. In the following example:

    static void Foo<T>(T t)

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    Given that both of these method calls are actually legal choices, I would say it is a much greater leap of faith for the compiler to choose one over the other, in contract to the case we have been talking about where one of the method calls <i>isn’t even legal</i>!

  52. Grico says:

    "Once again, you start your argument from the position that "[the] perfect match is illegal." That argument is a non-starter, because my contention from the very beginning has been that the illegal match is NOT the perfect match! It is only hard to say what the intention of the programmer is if you start from the position that what the programmer wrote is ambiguous or illegal. If you instead start from the position that what the programmer wrote is exactly what they intended, the right solution is obvious."

    We can all go in circles all day long here 😀 You claim that Eric’s argument is non-starter. Of course another prefect claim is that "what the programmer wrote is exactly what they intended, the right solution is obvious." is a non-starter too. Because thats precisely why the compiler throws an error, because it’s not sure that the programmer wrote exactly what they intended.

    C# is a language designed to avoid traps and pitfalls and if that means throwing an avoidable compile time error in lieu of risking doing something the coder might have not intended, well so be it. You can always go back to C++ where the compiler will let you happily wander into the realms of the unknown whenever you choose.

  53. Grico says:

    "static void Foo<T>(T t)

    static void Foo(Animal animal) { }

    static void Main()

    {

      Foo(new Giraffe());

    }

    Given that both of these method calls are actually legal choices, I would say it is a much greater leap of faith for the compiler to choose one over the other, in contract to the case we have been talking about where one of the method calls <i>isn’t even legal</i>!"

    No its not. Overload resolution is clear in this case. Generic method is an exact type and will be chosen except when an exact match of a non generic method exsits. In this case it doesnt, so I dont see the leap of faith anywhere. Anyone who knows how generics work understands that. And the main difference with the case Eric posted is that you’re example’s behavior is crystal clear independently of how complicated, extensive or massive is the code you are working in.

  54. jmeyer43 says:

    The spec clearly contradicts itself.  The italicized portion of the first spec quote clearly states that Foo(Reptile) cannot be a candidate method, which should be obvious to anyone (or anything, including the compiler) looking at the code.

    No, it does not. You are misreading the spec in exactly the way that I described. The “parameters” referred to in this part of the spec refer to the types of the formal parameters. The type of the formal parameter is “Reptile”, which isn’t even a generic type, so clearly it has not violated its generic constraints. It does not refer to the type parameters of the method or the constraints of the method. It refers to the formal parameter types, and the constraints on those types. I agree that this is confusing and could be more clearly worded. But this is not at all contradictory. — Eric

      The second quoted portion of the spec seems to imply the bizarre behavior the compiler displays, but since that behavior doesn’t make any sense and is clearly contradictory to the statement before it, I don’t see any way this can be interpreted to not be a compiler bug.

    That behaviour makes perfect sense, and is not contradictory. You might believe, as apparently several people do, that this was a poor design choice by the designers of the algorithm. But the behaviour is neither bizarre nor contradictory. The behaviour is carefully designed in order to find a bug in your code, and is consistent with the rest of the overload resolution algorithm. — Eric

     We have a call to Foo(Giraffe) with exactly 2 possibilities Foo(Animal) and Foo<>(Reptile), one of which matches and the other of which doesn’t.  

    No, both of them match. Matching matches only arguments to formal parameter types. The argument matches both. Constraints are not considered when matching; that’s the contentious point.  — Eric 

    Just because the compiler can use Foo<>(Reptile) as if it were Foo(Iguana) doesn’t justify assuming it can also use it as if it were Foo(Giraffe), Foo(Car), or Foo(string), after all the method IS Foo(Reptile), it is NOT Foo(object).

    No, it isn’t that, not at all. The method is Foo<T>(T), not Foo(Reptile). It doesn’t take a Reptile at all. It takes a T, a T which happens to be constrained to be Reptile. Again, Foo<T>(T) is not a method that takes a Reptile; it is a pattern that generates new methods, one new method for every possible T. The reason why the title of this post is “constraints are not part of the signature” is because constraints are not part of the signature. The formal parameter type is part of the signature, and the formal parameter type of Foo<T> is T, not Reptile. The formal parameter type of Foo<Reptile> is Reptile.

    Perhaps I should have chosen a different example. Suppose instead of the Reptile constraint, we had a new() constraint. Suppose Reptile does not have a parameterless constructor but Animal does. You pass a reptile to the method. Do you expect it to call the Animal version, or do you expect it to infer Foo<Reptile> and then tell you, hey, you got an exact match here, but the type you provided for me doesn’t have a public parameterless constructor? — Eric

    Obviously as a work-around Giraffe can be cast to Animal in the parameter list, but since Giraffe IS A Animal, we should be guaranteed that such a cast will not alter the compiled IL unless both types have an exact match, and in this case the only types having an exact match are Animal and, by generic rules, types that inherit from Reptile but do not have their own specific overload

  55. v.reshetnikov@gmail.com says:

    @jmeyer43

    > The italicized portion of the first spec quote clearly states that Foo(Reptile) cannot be a candidate method, which should be obvious to anyone (or anything, including the compiler) looking at the code.

    As Eric explained, "their constraints" in the italicized text refers not to constraints in the method declaration, but to constraints in declarations of types occurring in the method signature.

  56. DRBlaise says:

    @Grico – "C# is a language designed to avoid traps and pitfalls and if that means throwing an avoidable compile time error in lieu of risking doing something the coder might have not intended, well so be it."

    I have seen something like the statement above several times in this thread and I believe that this is the heart of the issue.  The problem is that this statement is NOT TRUE in C#, specifically in regards to method inference and generic type inference and extension methods inference.  Today C# is making all sorts of assumptions that risk doing something the coder might not have intended.  So why does C# decide to treat generic constraints differently and throw a compile error instead using the constraint to infer a valid method?  The only explanations I have seen are variants of the statement above and the statement simply does not hold for C#’s method inference logic.

  57. INTPnerd says:

    @ Lord Dust

    You said:

    <start quote>

    Don’t forget, the use of type inference is implied with every generic declaration in C#. So, when you write:

    static void Foo<T>(T t)

    you implicitly state "Whenever I make a call to a method named Foo, I MAY be calling this generic method, even if I did not specify a type argument. If you encounter such a call, please use this guide to create the method signature, using the type inference rules if necessary, and put that signature in the candidate list.".

    <end quote>

    This is exactly what I am saying should be changed, therefore you are making a non argument. You are basically saying that because the compiler currently defaults to the generic version, then this is what you are implicitly agreeing to. That is obviously true, but it has nothing to do with my comment. I was talking about what would be logical for the compiler to do, I was not debating what it currently does. I was pointing out that the calling code makes no explicit reference to specify that it is using the generic version. Since that is the case and there is another method that is not generic, which actually takes a parameter with a compatible type, and since the generic version has a constraint that makes it an invalid call, then there is no logical reason for the compiler to default to the generic version.

    Also if you think of the generic method as already having generated all possible methods based the available classes, then the original code becomes this:

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo(Reptile t) { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    Since there are currently no other classes that inherit from Reptile, then there is only one possible method that can be generated from the generic method, and it would take a Reptile. In the code above, the second Foo would be called. I do not see any good reason for the original code with generics to not behave that way.

    The argument by Eric where he defended defaulting to the generic version because this one might have better performance is going against his own statement about how they should not assume that they know better than the programmer what they want. Also if the generic method has a type constraint that means it would not even work with the same type as found by a non-generic overload, then there is a good chance that it is not simply a faster version of the same behavior, but different behavior entirely. Since the two methods probably have very different behavior, it does not make sense to default to the generic one when the calling code is all but explicitly specifying the non-generic method.

    Unlike what some of you seem to think, C# is not about explicitly specifying everything, and having compile errors every time you do not explicitly specify something. If that were the case, you would always be required to explicitly specify the type when calling a generic method.

  58. Eric Lippert says:

    I am curious about something. Those of you who think this rule is bad, read this code carefully. Note that Func is covariant in T and Action is contravariant in T in C# 4, and that C# 4 type inference takes this into account.

       class Animal { }
       class Reptile : Animal { }
       class Program
       {
           static void Bar<T>(Func<T> f, Action<T> a) where T : Reptile { }
           static void Bar(object x, object y) { }
           static void Main()
           {
               Func<Reptile> f = null;
               Action<Animal> a = null;
               Bar(f, a);
           }
       }

    STEP ONE:

    What happens in C# 4 is type inference reasons as follows. From the first argument we know that T must be Reptile, or a larger type. From the second argument we know that T must be Animal, or a smaller type. Both Reptile and Animal match both bounds. We choose Animal as the more general of the two and infer that T is Animal.

    STEP TWO:

    Overload resolution then has Bar(ob, ob) and Bar<Animal>(F, A) to choose from.  The latter match is a better match, so we choose it. Then we discover that this match violates the type constraints, and give an error.

    I understand that you believe that step two is wrong. You believe that Bar<Animal> should not be considered to be a candidate at all, since it is an illegal method. Fine. I accept that opinion as reasonable. You believe that applicable candidate checking should take into account factors which are not in the signature, like the generic constraints.  Fine.

    You therefore believe that this should choose the Bar(ob, ob) version, right?

    Hold on a minute there.

    Shouldn’t step one, the type inference step, also have taken into account the constraint? Because type inference had two types to choose from, Reptile and Animal, that both met all the checks required by the generic bounds.  Type inference chose to infer Animal because Animal was more general, and thereby chose to infer a method that is illegal. Type inference could have said “well, I could infer Bar<Animal>, but oh, that violates the constraint on Bar. Is there anything else I can infer? Yes, I can infer Bar<Reptile>!

    Had type inference done that, then the choice would have been between the object version and Bar<Reptile>, which DOES meet the generic type constraint, and is the better match. Surely the best thing to do in this case is to choose Bar<Reptile>.

    So my question for you is: is it your belief that method type inference should also take into account stuff that is not in the signature, like generic type constraints, when inferring the type arguments of a generic method call from the passed arguments?  Or should method type inference only take into account the stuff that is actually in the signature?

  59. Grico says:

    @DRBlaise "I have seen something like the statement above several times in this thread and I believe that this is the heart of the issue.  The problem is that this statement is NOT TRUE in C#, specifically in regards to method inference and generic type inference and extension methods inference.  Today C# is making all sorts of assumptions that risk doing something the coder might not have intended.  So why does C# decide to treat generic constraints differently and throw a compile error instead using the constraint to infer a valid method?  The only explanations I have seen are variants of the statement above and the statement simply does not hold for C#’s method inference logic."

    Please show me a case where the compiler assumes something. As far as I know the compiler never ASSUMES. It can infer types because it has all the information needed to be 100% sure it will do so correctly, it never assumes something to be true AFAIK.

    Second, I think Eric made it a lot clearer in a comment above. All the naysayers here are arguing that the obvious valid choice is the non generic method. I highly disagree and IMHO our case becomes clearer when we talk about a new() constraint.

    class Animal {…}

    class Dog: Animal

    {

       private Dog();

       …

    }

    void Foo<T>(T t) where T:new()

    void Foo(Animal animal)

    Dog dog;

    Foo(dog) //Compiler error. Does not verify constraint

    In this case more than ever I am grateful the compiler will issue the error it does.

  60. DRBlaise says:

    I love the example Eric!  Now I have another reason besides "C# does not try to read the developers mind"

    To answers your question: I believe that method type inference should take into consideration generic type constraints when inferring the type arguments of the generic method call.  After all, Bar<T> is an infinite list methods of all type T’s.  Method inference should be able to pick the "best" one that is valid per the constraints.

    Now that being said, I understand it might be difficult to do this, but in a perfect world it should be able to.

  61. David Nelson says:

    @Grico,

    As I have already stated, I am all for avoiding traps and pitfalls. The general explicit nature of C# is one of my favorite things about the language. But explicitness comes with a cost. The art of language design (as Eric has stated many times) is evaluating the benefit versus the cost. After all, if the only concern was avoiding pitfalls, we would just get rid of type inference altogether; that would be much safer than having the compiler guess what types the programmer intended to use when he didn’t actually state them. But (hopefully) you see why that would be a horrible mistake. We are willing to accept the relatively small risk of choosing the wrong type arguments in exchange for the enormous increase in usability that type inference provides.

    "Overload resolution is clear in this case.

    …[your] example’s behavior is crystal clear independently of how complicated, extensive or massive is the code you are working in."

    Why is it any more clear in this case than it is in the first code sample? Both generic definitions clearly define what types may be used in their type arguments. "Anyone who knows how generics work" can understand what is going on. It is the compiler that chooses to arbitrarily ignore one of the pieces of information that the developer had at his disposal when writing his call, thereby turning a unambiguously legal call into an illegal call, to the bewilderment of the developer who has written exactly what he intended.

  62. "So my question for you is: is it your belief that method type inference should also take into account stuff that is not in the signature, like generic type constraints, when inferring the type arguments of a generic method call from the passed arguments? "

    Yes yes yes yes yes!

    Now we’re getting somewhere. That’s exactly what I want!

    Going back to the original example of:

    static void Foo<T>(T t) where T : Reptile { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    My desire isn’t to consider Foo<T>(T) and Foo(Animal) both to be matches and *prefer* Animal. It’s to *fail to infer a valid T* for Foo<T> and therefore not consider it at all.

    I gave another example above:

    class Base<T, T2> where T : Base<T, T2> { … }

    class Derived : Base<Derived, D2> { … }

    static void Foo<T, T2>(T t) where T : Base<T, T2>;

    Foo(new Derived()); // should infer Foo<Derived, D2>

  63. David Nelson says:

    @Eric,

    Stuart hit the nail on the head. Type inference should infer the “best” type arguments to the generic method that will result in a legal call (which to me is part of the definition of “best”, but apparently it needs to be stated explicitly). If it succeeds, the resulting signature is added to the list of candidate methods; if it fails, the generic method is not considered. In this case that would result in a candidate signature of Bar(Func<Reptile>, Action<Reptile>), which would be preferred over Bar(object, object).

    On a side note, it is interesting to find out that given a range of possible type arguments due to variance, the most general type is chosen. I would have thought that it would be the most specific. But I haven’t fully thought through the implications of that, and it has been a long day. I will think about it more tomorrow.

    That’s for backwards compatibility with C# 3. In C# 3, there was no co/contravariance, so we considered all bounds deduced by inference to be “lower” bounds. (Even bounds we could have known were required to be exact; if the exact bound was not the most general then we would simply infer an inapplicable method, and it would be weeded out during applicability checking.) When every bound is a lower bound, it only makes sense to choose the most general of them; the highest of the lower bounds.

    In C# 4 we could have upper bounds as well. So we now track whether a bound deduced on a type parameter is upper, lower or exact. But to be compatible with C# 3, in bizarre situations like this where we need a tiebreaker, we go back to choosing the most general. If we didn’t have to be backwards compatible, then I suppose it might be marginally better to choose the more specific. — Eric

  64. Eric Lippert says:

    OK, how about this case? Suppose we are in C# 3, so, no variance, sadly.  You have a method that tells you if a given item is larger than every item in a sequence:

    static bool IsBoundedAboveBy<T>(IEnumerable<T> sequence, T item) where T : IComparable<T> { … }

    static bool IsBoundedAboveBy(IEnumerable sequence, object item) { … }
    // for backwards compatibility with a C# 1.0 version of this product.

    and we have

    class Fruit : IComparable<Fruit> { … }
    // Apparently you *can* compare apples and oranges

    class Banana : Fruit { }

    List<Banana> list = whatever;
    Banana banana = whatever;
    bool b = IsBoundedAboveBy(list, banana);

    My way:  The user clearly intended the generic version to be called.

    Type inference infers that the user meand IsBoundedAboveBy<Banana>(list, banana).  The match of list to IE<Banana> is better than the match to IE, and the match from Banana to Banana is better than the match to object, so the generic version wins. Since C# 3 does not support contravariance, unfortunately Banana does not implement IComparable<Banana> — it implements IComparable<Fruit>, a completely different type. The user gets the error that the type constraint has been violated. The user then fixes the problem by saying

    bool b = IsBoundedAboveBy(list.Cast<Fruit>(), banana);

    (Note that type inference cannot infer Fruit; in C# 3, IEnumerable<Banana> is not convertible to IEnumerable<Fruit>, so that would be inferring an inapplicable method. Type inference can only infer Banana.)

    Your way: A generic method which violates its constraints should not be applicable. The user knows that the generic method is not applicable because the user remembers that C# 3.0 does not have covariance on sequences, and the user also knows that type inference cannot infer any applicable method in this scenario. The user, who passed a generic collection, clearly meant for the pre-generics C# 1.0 legacy version to be used.

    Does your way still seem right to you in this case? Do you believe that the user *intended* to call the non-generic C# 1.0 legacy version?

    Or do you believe that the user does not realize that IEnumerable<T> and IComparable<T> are not co/contravariant in C# 3.0, and that a Cast<T> sequence operator is necessary?

    Is my way looking a bit more plausible now?

    — Eric

  65. INTPnerd says:

    Earlier I said:

    "Also if the generic method has a type constraint that means it would not even work with the same type as found by a non-generic overload, then there is a good chance that it is not simply a faster version of the same behavior, but different behavior entirely. Since the two methods probably have very different behavior, it does not make sense to default to the generic one when the calling code is all but explicitly specifying the non-generic method."

    I take back the part about how the non generic method would probably have very different behavior. This time I was the one not seeing it from the programmers perspective in a real world scenario. Normally the whole point of naming a method the same, is because it does the same thing. It would be very misleading to use overloading when one method does something completely different.

    Even so, I still stand by everything else I said. If this were a real world example, the two methods might have somewhat different behavior, but I would expect they would be very similar. The generic one may very well be faster, when it can be used, but if it can’t be used the compiler should not try to force you to use it and then have an error when it does not work.

    I will repeat this part one more time since I think I finally found a good wording: the calling code is all but explicitly specifying the non-generic method.

  66. DRBlaise says:

    Hhhmm, your starting to convince me, Eric.  With the history of generic and non-generic interfaces of the same name that C# has and the lack of support for contravariance, I can see that unintended methods calls could happen more frequently than I thought.  Add into that the practical considerations of keeping things simple and the amount of effort to implement the new logic and it definitely makes since NOT to consider the constraints in the inference logic.

    Thanks for your efforts to explain all reasons!

  67. INTPnerd says:

    Eric,

    The fruit example is definitely a better example for defending your case. It was a good response to those who asked for such an example. This example does illustrate the complexities of generics and how no matter how you choose to implement the compiler there are going to be times when something unexpected happens due to the complexity.

    After reading this example, I was at first thinking that maybe it should select the non-generic method, but also issue a warning, something like: "There is a generic method with the same name, are you sure you did not mean to call the generic method?". Then I was thinking that this would be an annoying warning because it would always cause the developer to change their code in some way to get rid of the warning, in which case there may as well have just been an "Ambiguous Call" error message. Also I don’t think they should feel obligated to change anything. This is especially true since our error messages and warnings are shown together in VS. Yes you can disable the warnings from being displayed, but I think most of us like warnings, and try to get rid of them.

    Now I am thinking that this illustrates the need for something other than just errors and warnings. It might be called "possible pitfalls", or something like this. Maybe these should be displayed in the same place as the errors and warnings, but be disabled by default. You could enable them once in a while (with a single mouse click without navigating menus) to see what is there. There are already tools that examine your code and make recommendations. This would be similar, but would be part of the compiler and built into VS.

    I think this would be a reasonable way to mostly please everyone and would be a useful feature.

  68. Eric,

    That’s why God invented [ObsoleteAttribute]!

    Your example seems like a perfect scenario for it – you may want to call the older version of the method but you probably want to be aware that you are doing it rather than have it happen accidentally.

    Bear in mind too that your scenario is only problematic because your old, pre-generics method is actually wrong: it should be IsBoundedAboveBy(IEnumerable sequence, IComparable item). Since Banana does not implement IComparable, the pre-generics method isn’t applicable anyway.

    (By the way, I’d be quite happy if IComparable and IEnumerable and all the other pre-generics interfaces got marked [Obsolete] in the 5.0 framework, personally, now that covariance and contravariance exist that pretty much eliminate all remaining reasons why you might want to use them).

    Also, we’re not talking about making this change in C#3 where covariance didn’t exist. We’re talking hypothetically about how we’d like to see inference changed in C#5. And I presume you’re not considering taking away variance in C#5! 🙂

  69. Pop.Catalin says:

    “static bool IsBoundedAboveBy(IEnumerable sequence, object item) { … } “

    This method is not how it should be written in C# 1.0, because it won’t work unless the item implements IComparable which it doesn’t.

    The way it should be is:

    static bool IsBoundedAboveBy(IEnumerable sequence, IComparable item) { … }

    in which case the non generic method is also invalid to call, unless the Fruit class implements IComparable.

    Let’s say it does:

    class Fruit : IComparable<Fruit>, IComparable { … }

    Then the proper way to write the IsBoundedAboveBy method in C# 3.0 is :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    class Program
    {
       static bool IsBoundedAboveBy<T, U>(IEnumerable<T> sequence, IComparable<U> item) 
           where T : U, IComparable<U>
       {
           return item.CompareTo(sequence.Max()) >= 0;
       }
       static void Main()
       {
           IsBoundedAboveBy(new List<Banana>{new Banana()}, new Banana());
       }
    }

       class Fruit : IComparable<Fruit>, IComparable
       {
           public int CompareTo(Fruit other)
           {
               Console.WriteLine(“Generic”);
               return 0;
           }

           public int CompareTo(object obj)
           {
               Console.WriteLine(“Non Generic”);
               return 0;
           }
       }

       class Banana: Fruit
       {   
       }

    this prints “Generic”. Also no casts are required using Cast<T> method or C# casts. This is perfectly cast free generic way to write the method in C# 3.0, the goal of no casts using generics is achieved.

    Another way to write IsBoundedAboveBy is :

       static bool IsBoundedAboveBy<T, U>(IEnumerable<T> sequence, U item) 
           where T : U
           where U : IComparable<U>
       {
           return item.CompareTo(sequence.Max()) >= 0;
       }

    But because type inference doesn’t take into account constraints this fails with the following error:

    The type ‘Banana’ cannot be used as type parameter ‘U’ in the generic type or method ‘Program.IsBoundedAboveBy<T,U>(System.Collections.Generic.IEnumerable<T>, U)’. There is no implicit reference conversion from ‘Banana’ to ‘System.IComparable<Banana>’.

    I agree with you completely that there are better ways to write methods with the implied semantics than the sketch I’ve presented here. But noting that does not change my point in the least.

    First off, not everyone has the benefit of working with well-designed code written by people who clearly understood all the subtleties of both the type system and the overload resolution algorithm. Lots of people work every day with code they didn’t write and cannot change which nevertheless fulfils some vital business purpose. The compiler has to handle imperfectly-designed code every day.

    Second, my example was merely intended to be illustrative of the sort of situation that could arise. I could have written an example with nothing but Foos and Bars in it, so that you would not have any intuition about what the semantics were, and therefore would not have any intuition about how to rewrite it so that it better expressed those semantics.

    My sketch merely illustrates that I believe that the statement that it is always the case that the developer intended to call the non-generic method, and therefore it should be considered the best one if the inferred generic method is invalid, is not correct. We can come up with plenty of situations in which the developer more likely intends to call the generic method. My point is that the compiler cannot know what was intended; if inference cannot work out something that works, then we don’t know what was intended and the right thing to do is to stop and ask for directions, rather than blazing along a different road. — Eric

     

  70. Anthony P says:

    The behavior is what it is and as long as people know, they should be able to live with it and code around it if necessary. Why not add something to generate an informational message whenever someone uses a non-generic method and a generic method with a constraint? It would inform the developer of the consequences and subtly invite them to investigate whether their code will execute as intended while not offending the "warnings are errors" crowd. "Constraints are not part of a method signature. If you have Foo(object o) and Foo<T>(T t), Foo(object o) will only be called with an object, not anything that is compatible with object without an explicit cast." Word it however and cater it to the specific usage, but that’s the net result of things, and it would at least curtail developer frustration with future versions of C# without breaking anything.

  71. Eric,

    "My point is that the compiler cannot know what was intended; if inference cannot work out something that works, then we don’t know what was intended and the right thing to do is to stop and ask for directions, rather than blazing along a different road."

    – yes, but (once you introduce the idea that the library may not have been designed optimally) that’s true of your way too! Consider:

    static void Feed<T>(T t) where T : Animal { … }

    static void Feed(Fish fish) { … fish need special handling to make sure they aren’t overfed … }

    Obviously this is a bad way to design an API because it does all kinds of wrong things if the compiletime type doesn’t match the runtime type. But for simplistic uses it does the job – UNTIL someone introduces class Goldfish : Fish { … }.

    Your way: We infer T=Goldfish and then Feed<T>(T) is an exact match, better than Feed(Fish).

    Note that I’m not making any concrete proposal as to how to address this problem or even saying that it’s a real problem that should be addressed. I’m just pointing out that the current system *already* has cases where it "blazes along a different road" than what was intended.

    Also, I think you are missing Pop.Catalin’s main point, which isn’t just that there are better ways to write the IsBoundedAboveBy method – but that one of the better ways to write that method doesn’t work *because* type inference doesn’t consider constraints.

    I’ll admit that your posts are making me reconsider my position, but I’m not ready to give up completely on the idea that inference should take into account constraints. Mainly because it’s not always about ambiguity between a generic and non-generic method (my codebase is self-contained, so my generic methods don’t have back-compatible versions, usually) – sometimes it’s about being able to infer something versus not being able to infer anything at all. Like my <Derived, D2> case, or Pop.Catalin’s second version of IsBoundedAboveBy. Is there really no way to get the best of both?

  72. How about an approach something like this:

    If a generic method potentially matches, then inference is attempted taking into account the constraints. If this *succeeds* then the method is called. If it fails, then we get an error that no valid type parameter could be inferred for T – even IF there’s a non-generic method that would otherwise be applicable and work.

    That would give something of the best of both worlds. Foo(new Giraffe()) in the original example fails as it does today, although with a slightly less confusing error message (which may take into account the fact that there’s a non-generic method you might want to call instead and highlight it for you – treat it as an ambiguity error). As does Eric’s version of IsBoundedAbove in yesterday’s post.

    However, *unlike* today, Func<Reptile> f = null; Action<Animal> a = null; Bar(f, a); from Eric’s post on Tuesday *succeeds* with T=Reptile, because it can, rather than failing on T=Animal. And Pop.Catalin’s static bool IsBoundedAboveBy<T, U>(IEnumerable<T> sequence, U item) where T : U where U : IComparable<U> can potentially succeed too, along with my Derived, D2 scenario.

    Thoughts?

  73. TheCPUWizard says:

    While I see the point that:

      void foo<T>(T p) where T: Reptile {}

    could easily be replaces with a non-generic.

    There are many other cases where it does matter. Consider

      T bar<T>(T p) where T: Reptile {}

    If this was replaced with a non-generic, then the return type would (obviously) always be Reptile.

    While the new co/contra variance cababilities do change the situation a bit, I believe that the signature of bar (above) is very clear that the return type will be exactly the same(or further derived)  type as what ever is passed in

  74. Josh Perry says:

    It almost seems like type constraints are what concepts are in C++ http://en.wikipedia.org/wiki/Concepts_(C%2B%2B), allowing the developer to codify his intent for the type parameters so that misuse will emit a useful compile-time diagnostic.

    Honestly it makes absolutely no sense to write "Foo<T>(T obj) where T : BaseType" if you are expecting the constraint to be taken into account during overload you might as well write "Foo(BaseType obj)" because obviously your code relies on some interface of the BaseType class for operation (interface? huh?).

    I agree that these are what they are, merely diagnostic hints by the developer. The problem is that we have this feature who’s use is mainly to diagnose the misuse of another feature which doesn’t exist. The fact that this feature breaks single responsibility is where the confusion arises.

    class Animal {

       public void Eat() { … }

    }

    void Foo<T>(T obj) {

       obj.Eat();

    }

    The compiler also gives an error here, of course "’T’ does not contain a definition for ‘Eat’" is not as helpful as "The type ‘Person’ cannot be used as type parameter ‘T’ in the generic type or method ‘Foo<T>(T)’. There is no implicit reference conversion from ‘Person’ to ‘Animal’". Though I’m not sure if the latter much more succinctly signals the intent of the writer of Foo<T> to the consumer, in fact this error could automatically be inferred if the type T didn’t have a member function Eat.

    That people are attempting to use constraints (and some quite vehemently expecting it to work) in the way that this post dictates is improper perhaps speaks to the need for something more powerful than simple generics, along the lines of specialization in C++. I know that I would use it quite often.

    Though I think metaprogramming in C# could cause a whole heap of mess for you guys, though they may be able to sway some more of the die-hard C++ guys over to C# (Deterministic finalization for use with SBRM would bring the rest probably!).

  75. Darren oakey says:

    A lot of us have come from c++ and think that not having specializations is a very bad thing – constraints seem to be the ideal engine for implementing such things – I understand your agruments about implementation, specification and so on, but I have to agree with the beelief that the way you are lookin at it is just wrong – if you define the constraints to be part of the signature, and allow overloads that differ only on constraint – you still have a completely consistent, working model – the only difference is that you can’t wait until later to check the constraint

    now, I wouldn’t advocate wholesale use of constraint specialization, but there’s one example that constantly comes up –  often you want to differentiate between where t: class and where t:struct, because you want explicit null handling that doesn’t make any sense at the struct level – default(t) doesn’t cut it- so you end up doing checks at runtime, which at minimum causes unnecessary boxing… Allowing specialization of methods based on constraints, especially those two, would introduce no potential ambiguities, but would be extremely useful to the developer, and particularly provide a compile time solution to a problem that currently only has a runtime one

    thanks,

    Darren

  76. Alvaro Dias says:

    @Eric

    While I tend to agree with what you’ve said (after going through the examples), there are a few things that came to my mind. I’m not saying that I have a solution to any of these, but

    1. you’ve said that the constraints are not part of the signature. Yet, to a developer looking at the code the syntax does make it look like it very much is.

    It would be great if somehow it could be made very very obvious to the user that the constraint is not part of the method signature and a mere diagnostic constraint if you may say so.

    2. You stated that a generic method is like a pattern " there is a pattern for generating infinitely many additional methods called Foo, the pattern is called Foo<T>".

    Consider

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    class Lizard : Reptile { }

    static void Foo<T>(T t) where T : Reptile { }

    Now to my assumption, which might be a totally wrong way to interpret the whole thing.

    I’m assuming that Foo<T> gets expanded into Foo(int t), Foo(Animal t), Foo(Reptile t), Foo(Giraffe t), etc. What confuses me is when this expansion happens, isn’t it possible to use the constraint so that it only gets expanded to Foo(Reptile t), Foo(Lizard t) and ignore the rest since the constraint is not satisfied?

    3. Consider the following code. It’s a perfectly working code.

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    It’s a perfectly working code. Now consider this.

    class Animal { }

    class Mammal : Animal { }

    class Giraffe : Mammal { }

    class Reptile : Animal { }

    static void Foo(Animal animal) { }

    static void Main()

    {

       Foo(new Giraffe());

    }

    static void Foo<T>(T t) where T : Reptile { }

    Addition of a new generic method without altering the existing code now produces a compile time error which is something I wouldn’t expect.

    Initial code is working. Adding a new method which doesn’t satisfy the call being made shouldn’t stop it from executing another method which it was already executing earlier.

    I may not have put point #3 in a well worded manner. I hope you get my point.

  77. Darshan says:

    I agree with what you say. It is language designer’s choice what is the spec and follow correctly.

    But, I am wondering Why is compiler is not giving a good message mentioning what method it has inferred to make life of a developer easy.  Something Like "Cannot convert Giraffe to Reptile. Using Foo<Giraffe>.”

    Because ultimate goal of compiler error is to make developer’s life easy so that it doesn’t do that mistake again.

  78. Stephan Keil says:

    @alvarorahul

    I am not sure which behaviour I would prefer in the mentioned examples, but thinking about your #3 reveals a more subtle – and thus more dangerous – behaviour when introducing a new method:

           static void Foo(double v) { }

           private static void Main() { Foo(4711); }  // calls Foo(double)

    Now add a new method:

           static void Foo(double v) { }

           private static void Main() { Foo(4711); }  // calls Foo(int) now!!

           static void Foo(int v) { }

    => Oops

  79. Alex G says:

    When it comes to what Eric says, I usually like his cold logic facts and dislike his opinions 🙂

    In this case, his cold logic is out in full splendor, I’m surprised the article made so much noise…

    It’s very simple, generic type parameter constraints are not mutually exclusive in the way that method signatures are, and C# is not a fuzzy language, so there is nothing incorrect here, and it’s been perfect like that since 2.0.

    Well, perfect is a big word… the fact that this debate is so big does point out a certain flaw, not in interpretation, but in syntaxic design: there could be a clearer distinction between the part of a method’s declaration that is considered a signature and the other parts.

    It’s hard to argue against the fact that the signature is sort of sandwiched in between the modifiers and the constraints, which often end up all on the same line, and that makes many people assume the compiler will take all of it in consideration. Well, screw them, it won’t compile, thankfully.

    That said ——-

    I have something else for a sparkling debate. There is one wall of C# I find myself grinding against ever so often. The class constructors and abstract static members. They cannot be inherited or passed up to derived class types.

    This means that even when using a generic type constraint, only the default constructor of that type can be used, because the passed instance could be a derived type, whithout the constructors, or what I would call a constructor contract. I supposed this is because constructors are a form of static method, and static methods are not inherited….

    Oppositely, in Object Pascal extensions X3J9/IEEE P770, there can be abstract static methods, and constructors can be inherited and overriden… and didn’t Anders Hejlsberg have a hand in that genius?

    Keep up the amazing work!

    Best,

    Alex

    contact at alexgrenier.com

  80. steve p says:

    My primary concern is for Eric’s fingers.  If you reacting to every comment you’ll end up with carpal tunnel and be sporting one of those silly "casts" when you go out.  Doesn’t impress chicks.

    C# spec and complier already determined this behavior so those of us who aren’t fans can live with it.  I believe it is the best language out there, but it ain’t perfect so we can deal with it’s idiosyncrasies.  We got better things to do

  81. Tahir says:

    I’ll disagree with the specification. I already created a request on MSConnect and will raise this point once more here: constraints should be part of the signature. Eric says "the best match is not viable", but I think the matching should take constraints into account because they directly affect the outcome since the matching is based on parameter types.

    It’s like looking for a girlfriend: using Match.com and finding the perfect partner – doesn’t smoke, likes Chopin, and plays volleyball – and then discovering that it’s actually a boy.

    I also created a MSConnect request to allow static members on interfaces, which goes closely together with abstract static methods on classes. Both this and the other request I mentioned were denied despite the fact that they make sense to a lot of developers.

    Ability to specify parameters on generic’s type constraint is also some times needed.

  82. quetzalcoatl says:

    Abstract static? I’m sorry, but that completely doesn’t make any sense. Please go back to basic OO definitions. Abstract/virtual has only sense when talking about OBJECTS. If you want to have abstract/static on a class, that I am 100% sure that you have missed some points in the design of your code, and you actually have messed up with static-class vs. singleton choice. Or maybe you are going into virtual extension functions, or, break the class/object distinction like in Ruby (it’s not the best wording, I know..)?

    But, I agree with arguments about including information from typeparams and constraints when trying to find a best match — currently, the mechanism very much looks like rules borrowed from C++/template overload resolution and is counterintuitive that the compiler chooses to take the generic

    but#1 – please take care when talking about generics. Even Eric has written, that a generic is a ‘infinite group of possible methods’. It is NOT! I hope that everyone in the discussion exactly understands that and that was just the logical shortcut. Still, I have to say: a generic thing is an exactly one thing, it is well defined, it has complete (at time of compilation) set of constraints/baseclasses/innertypes/members/etc. It is VERY opposed to the ‘infinite number of possibilities’ offered by C++ templates & specializations: there, at the point of usage of a template, the compiler had no idea what the poor template will actually look like, the only sure thing was its name (preprocessing step is done, all the text is known) thanks to forward declarations in header files. Only after (pre)compiling just everything, the compiler gains knowledge about what specializations of that template are actually defined, and what members those specializations actually do have (as in C++ it is valid to have template specializations class MyClass<int>{  float myfield; }  and MyClass<float> { complex pleasenoticeDifferentMemberName;} ). This is the main cause why in C++ there is a TYPENAME keyword that allows the compiler to assume that some code constructs actually WILL be later defined as inner types dependent on the compile-later template specialization, and why some compilers implement multiple compilation passes just to support the ever-wanted EXPORT template keyword..

    —-

    Historical thingies said, so now, backing to the original discussion iwth some constructive criticism:

    A single generic is an exactly one instance of code definitions. It has no specializations (pity, but extremly considerable design choice, as it simplifies much in what I have said above in C++) and its contents at the compilation pass that performs overload resolution are completely well known. I don’t know how the C# parser-compiler is built and how many steps it has, but it is sure that when METHOD overload resolution is performed, that is, when bodies composed of blocks of statements are compiled and concretized, the types MUST be known, because processing bodies would have completely no sense. In C++ you HAD to process bodies to check bodies to see what members COULD have be there to choose the right specialization, see SFNIAE/SpecializationFailureIsNotAnError rule. In C# as you already know the types, you already know the base classes, members, the formal parameters, the type constraints, the (..) and now, as you are processing the MEMBERCALL, you even have at your had the actual types of the formal parameter. There is actually no reason why you couldn’t be able to select not only the BEST MATCH, but you should even be able to select the BEST VALID MATCH at this point.

    If you reason that this is not affordable in terms of effort needed to implement, or that selecting best-valid over best-any it’s counterintuitive to some group of programmers, or you want to have a language with clear rules, or .. (I don’t want to cite everything), then, in my opinion, the only actually reasonable way to solve the problem was to NOT SOLVE it at all. Do not enforce the way the compiler chooses methods now, as it is obscure for all that have not lost their teeth on C++ for whom whole C# and its mechanisms is plain trivial. If you wanted to have clean rules, and you have stumbled upon such amiguities/unimplementabilities, I think the valid action was to prohibit name overloading between generics and nongenerics at all, and leave it clearly disallowed and unsupported due to underlying problems, either algorithmic or time/financial. That would leave the situation clear: compiler cannot decide, please choose different names to be explicit.  If still want the same names for generic/nongeneric, you could had enforced explicit indication of which of those kinds of method the compiler should be searching through. If a mark is given, search only through generics or nongenerics as marked, else if mark is not given, search through whatever but raise ambiguity error when a mixed types are found.

    Forgive me the syntax and trivial example, but it’s just for the glimpse on the idea:

    class X
    {
       void method(blah prm);
       void method<T>(T prm);
       void another1(blah prm);
       void another2<T>(T prm);
       void codeblock()
       {
           another1(null);  // no indication – look anywhere – no collision – obvious match another1()
           another2(null);  // no indication – look anywhere – no collision – obvious match another2<T>(), T=object
           method<Int32>(null);  // indication: explicit type param – no search at all – match method<T>(), T=Int32
           method<?>(null);  // indication: look in any generics – no collision – match method<T>(), T=object
           method<!>(null);  // indication: look in any nongenerics – no collision – match method()
           method(null);  // no indication – look anywhere – collision! – error: cannot decide what’s best, generic or nongeneric
       }
    }

    As for me, it would be better than current, and than than proposed find-best-valid, and probably for the compiler implementor, too – as the inference/overload resolution woudl be simplier. For programmers? I see the syntaxes:

      identifier<typename> for saying explicitly what type param must be used

      identifier<?> javalike construct, for meaning any generic instantiation is allowed

      identifier<!> new one, for indicating that NO type param at all is allowed – thus forcing nongeneric

    are easy to read and easier to comprehend than this whole discussion and its origins 🙂

    Such syntax may seem superfluous, but it clearly would indicate whever we:

    – do not care where the compiler searches or are sure there is only one option due to the name uniqueness

    – or we exactly know that we want to search through that one subset of possible matches

  83. Jeff Yates says:

    If you are of the view that T is more specific than a base type because T can be the exact type being passed, then the current behavior makes sense.

    However, if you believe that specifying a generic parameter, T, actually is less specific than a base type, then the current behavior seems wrong. Unfortunately, the term "generic" makes this even worse because it implies a lack of specificity and I think it leads people to believe that it would be checked LAST when inferring types such that the base type took precedence. And that’s before we even consider the constraints, which as stated, are not part of the signature (even though some feel that perhaps, they should be).

    Type inference appears to be very hard (I admit that I struggled to follow the entire discussion here) and my impression is that whichever route were to be taken, there would be some who claimed it was doing the wrong thing. Considering that, it makes sense that any ambiguous situations be raised as an error wherever possible.

    Damned if you do, damned if you don’t.

  84. Alex G says:

    RE: "Abstract static? I’m sorry, but that completely doesn’t make any sense. Please go back to basic OO definitions."

    I understand this is off topic, yet your argument is compelling, you make a strong point… but it’s not something I invented. It’s also not a departure from OO at all. Runtimes can abstract symbolic execution, static members can be called dynamically, etc, hoops and loops to do simple things… therefore static contracts totally make sense, especially in a language where types can be passed as parameters with constraints.

    For example, if I have a generic method RemoteAction<T>(T client, Action action) where T is constrained to AbstractServiceProxy, and AbstractServiceProxy has a static contract SIRemotingClient declaring a factory method T Create(string remoteAddress), any type descending from ServiceProxy would be known to have a static method T.Create(string remoteAddress) callable from inside the generic method. Or T could be constrained to SIRemoting, enabling any class to implement the static contract and be usable with the generic RemoteAction method.

    Now take this concept and adapt it to form constructors contracts, it would enable to do T foo = new("bar") from inside generic methods.

    I hope now you can make some sense out of it 🙂

    Happy coding!

    Alex G

    contact at alexgrenier.com

  85. Nick says:

    I’m not the most experienced programmer compared to any in the thread, not even close.  But here’s my 2 cents…

    I agree with both arguments and appreciate the compiler preventing possible bugs at any chance especially when it might be a bug thats hard to pin-point.

    Perhaps in this situation because there is apparently a demand to circumvent the compiler’s error.  Maybe there could be a compiler switch to allow it, say… [isCludgable].  I know that goes against C# logic since it is very strict, which I appreciate and would never want to stray from or start creating exceptions to the rules.

    Either way its damn near impossible to make everyone happy since there will always be an argument for or against.

  86. quetzalcoatl says:

    "static contracts totally make sense"

    vs. "to allow static members on interfaces, which goes closely together with abstract static methods on classes"

    Please don’t take my words in too general scope – I am totally for any static contracts, be them simple ‘where’ or an static interface spec! Together with generics, static interfaces would be great. Oh, I’d lova to be able to write something crazy like "T meth<T>(){  return T.Parse("d2"); } assuming T implements some static interf and theres proper constraint on T, instead of writing special Parser/Converter class that implements 1 method from a 1 method interface that I must artificially include as yet another type parameter… [By the way, currently I like to solve that via ‘extension points’ or ‘fill-my-algorithm’s-holes’ pattern via Func/Action].

    I just disagree with >static abstract/virtual< . That doesn’t make sense for me. Thinking around it bit more -assuming static abstract does have sense – base class allows usage of BaseClass.staticMethod but doesn’t implement it and passes implementation to the children.. ok. that is partially sensible But static virtual? Maybe, if someone insists, the same reasoning down class hierarchy. (that doesn’t mean I agree 🙂 )

    But, statics have only three reasons of existence:

    – you want to protect the object’s internals from the methods code – make it static, separated

    – you want to have a ‘library’ function loosely connected to the class that does arbitrary (external?) things on the object

    – you actually want to have a global instance manager/factory/etc

    For all those cases, when case is trivial, such statics are trivial to implement, and don’t need abstract/virtual.

    IMHO, for all those cases being nontrivial …it shouldn’t be solved by a static, but new classes, that would separate better and clean the code lying around a bit more

  87. Alex G says:

    No, not static virtual, that actually doesn’t make sense for real, since virtual calls require instances obviously…

    I meant static abstract only in the sense that a method’s existance, it’s parameter signature, generic constraints and return type can be declared separately from its implementation, which is impossible right now in C# for static members. But the contract could be specified through abstract static members on class definitions, or static members on interface definitions. Of course this would require a C# language modification.

    But even with no language modifications, just some funky type builder tricks, the static methods of a type could be accessible once there is a generic constraint on that type parameter. This does not present the same issue as constructor contracts, since deriving types are known to also have static members, whereas the constructors of deriving types are unknown. So, Type.MakeGenericType could totally handle this, and although the constructors would be unknown, we could have static factory methods. 🙂

    Happy coding!

    Alex G

    contact at alexgrenier.com

  88. Ryan Riley says:

    I didn’t make it all the way through, but I agree with those saying this appears to be a "spec bug" while also agreeing with those who say having those two methods in the same class is a mistake. Unfortunately, I’m also thinking that, since the type constraints aren’t apparently useful except for intellisense noise reduction, I can’t think of a reason why I would ever use type constraints again unless the compiler requires it for setting an object to null (i.e. where the class constraint is required, though you could get around that with default(T)).

    If I’m wrong, why would I care about constraints anymore? I could use guard clauses or Code Contracts to do the rest and get a better, imho, response than the type constraint.

  89. Greg says:

    I really do think that the average C# programmer (the type that didn’t read the spec) would consider this a very confusing error.

    "Why are you doing this to me and how can I get you to stop doing this to me" might be the initial reaction of an average programmer when encountering this error.

    Since it’s impossible to determine the intent of an illogical programmer, giving some guidance on possible intents and their implementations (delivered somehow through Visual Studio) to said illogical programmer, when they act illogically, would go a long way to alleviate stress/anger when encountering this.

    Or, in otherwords, help people to "stop worrying and love the bomb"

  90. Pete Hurst says:

    For anybody still thinking this is a language defect that needs to be fixed, can I quickly remind you that in the original example, there is a simple way to rewrite the function signatures to ensure there is no ambiguity:

    static void FooReptile<T>(T t) where T : Reptile { }

    static void FooAnimal(Animal animal) { }

    By changing the method names to better describe their purpose, you have removed any possibility of ambiguity, and made your methods more descriptive. I believe this was the intention of the C# designers, and a good one.

    It’s all well and good having the compiler infer which method you are after, but it’s very simple when you only have two same-named methods. Suppose we add another 10 for various different types of animal, all of which are sub-classed from each other in various complex ways. How then can the compiler guess which one you need when you throw a different type at the ubiquitous Foo? How can *you* even work out which one you are targetting? What happens if you start refactoring your animal classes and somehow change the hierarchy of inheritance? Suddenly you have thrown the bath out with the baby and have no idea which calls are going where, but the compiler isn’t giving any errors to tell you where you might need to fix things!

    I personally am glad that there is good sense and forethought behind such language decisions in C#.

    Thank you Eric for an informative and useful article.

  91. Pete Hurst says:

    @Alex G:

    I just noticed this in one of your comments:

    "The class constructors and abstract static members. They cannot be inherited or passed up to derived class types."

    Class constructors *can* be used by derived types. It goes like this:

    public class Animal {

     public string Name;

     public Animal(String name) {

       Name = name;

     }

    }

    public class Giraffe {

     public Giraffe() : base("Giraffe") {

       // Animal ctor is called first. Follow with Giraffe here.

     }

    }

    You can call any constructors of a parent class in this way.

    Pete

  92. Gboyega Suleman says:

    I think the problem is defined in the topic of the write-up – "Constraints are not part of the signature" which to me is a bug.

    Why because I believe overload resolution should not be completed independent of the constraint applied on each method where found.  

    That overload resolution selects a method it thinks is best match, discard all the rest and then go back to apply the constraint to the one it has already decided is the best match means we can always run into this and will always confuse us.  

    It also means overload resolution should be revisited to included constraint vetting in its resolutuion process and since this cannot be done, its better to admit this as a gap, perhaps and let us all know so we code along line, but I will not agree that it is we the developer that gets it wrong here, because what we are trying to do here isperfectly legitimate.

  93. Colin Smith says:

    Eric, you said in an early comment:

    "No, there is one non-generic method called foo, and there is a pattern for generating infinitely many additional methods called Foo, the pattern is called Foo<T>. — Eric"

    But the method has a type constraint, so "Foo<T>(T t) where T:Reptile" is actually a "pattern for generating infinitely many methods called Foo, all of which take a Reptile or a subclass of a Reptile"? I would argue that the compiler should not generate a Foo<Animal>(Animal t), nor a Foo<int>(int t) because the type parameters don’t match.

    If this was implemented, the compiler then wouldn’t generate the ‘better’ match and the call to "Foo(new Giraffe())" would hit Foo(Animal animal) as intuitively expected by most people here. All it requires is for the compiler to be a little cleverer and to take into account the type constraints when generating the methods that satisfy the generic pattern.

  94. Tahir says:

    quetzalcoatl,

    Alex G’s response pretty much sums up my opinion as well. Static virtual won’t work, of course – but static abstract will, if used in a generic context. For ex.:

    abstract class A

    {

    public static abstract F();

    }

    class B:A

    {

    public B(int a, string b) { .. }

    public static override(?) F() { .. } // override keyword probably not needed IMHO

    }

    class C:B

    {

    public C(int a, string b) { .. }

    public static override(?) F() { .. } // override keyword probably not needed IMHO

    }

    void Bar<T>() where T:A, new(int, string)

    {

    new T(1, "a");

    T.F();

    }

    Bar<B>(); // will call B.F

    Bar<C>(); // will call C.F

    Pete Hurst,

    I disagree. It doesn’t matter how many overloads you have, the rule is simple – find the best match. If you look at this from abstraction POV, if you change the hierarchy or any of the overloads, that shouldn’t concern the "outside world" of some code calling the method. Whatever the overload structure is, calling the method Foo() should produce the required result. The only additional requirement is a simple recompile of any other assemblies that make use of the assembly containing those methods. If you go down your route of naming each method differently, you end up 1) with a huge number of names to maintain, and 2) in case where you add a new overload, or remove an existing overload, all "client" code needs to be changed – as opposed to just recompiled, which introduces more work.

  95. Brannon King says:

    This is a big inconsistency with the way extension methods were implemented. If method resolution only works on the object parameter footprint, adding a where clause to an extension method should chuck a compile-time error. Why would we want our extension methods showing up in intellisense on all inheritors of object? It’s lame. Absolutely we should be considering type constraints as part of the method resolution process. This makes extension methods infinitely more useful and user-friendly.

    I’ve wanted to enhance the ability of the "where" clause for some time. I’d like the ability to specify "where T: operator+, operator-,operator(int)", aka, add the ability to require certain operators or casts on types. I think that would have accomplished the same thing as the dynamic keyword in 90% of the general "object" usage without reducing the compile-time type checking. In other words, it appears that the dynamic keyword is just a patch for an unwillingness to address the inconsistent method resolution rules (similar to term limits being a patch for the 17th amendment as we don’t have the political will to address the real problem…)

  96. Tahir says:

    Brannon,

    Nice idea about the operators – I agree that constraints need to and can be enhanced in many ways.

  97. Alexander Fedin says:

    You know what sounds really weird to me? The fact that there was a bug introduced in the spec that causes the very inconvenient behavior, and the other fact that instead of fixing both the spec and behavior, guys the are proudly protecting this bug from to be fixed.

    Anybody can look from this perspective?

    Eric?

    In order for there to be a “bug” there has to be an error. In this case, the spec is exactly the way we want it, and the implementation is a correct implementation of the spec. That the language was not designed the way you think would be better isn’t a bug, it’s just a disagreement between you and me about what the better design decision would have been. The documentation of that design decision is sound, as is the implementation. There’s no bug here to be fixed, in either the spec or the implementation.

    This is a feature. This feature finds bugs in your code and tells you about them rather than hiding the bug from you and doing something wrong. I do not understand why C# programmers think that’s a bad thing; C# programmers typically want to be told about the bugs and ambiguities in their programs so that they can be assured that their program is doing exactly what they intend it to be doing.

     — Eric

  98. Sam says:

    It seems to me that the flaw (in the spec) is that the generic constraints are not part of the signature of the method.  These constraints are statically enforced and are therefore deducible at compile time and I can think of no better way of allowing the developer to reveal their intention.

    It also seems very conterintuitive that

    static void Foo(Animal animal) { }
    static void Main()

       Foo(new Giraffe());
    }

    compiles fine but

    static void Foo<T>(T t) where T : Reptile { }
    static void Foo(Animal animal) { }
    static void Main()

       Foo(new Giraffe());
    }

    does not.

    If you are trying to read the intentions of the developer: 1) give them mechanisms for stating their intentions (such as generic type constraints) and 2) have the compiler use those mechanisms to disambiguate.

    How does that work, unless the developer writing the callee is the same as the developer writing the caller? That is frequently not the case.

    As I’ve said now over ten times in these comments: we assume that the programmer writing the call site intends to call a particular method, and communicates this by selecting arguments which overload resolution will use to choose a particular matching signature. When the programmer’s intention cannot be unambiguously determined by matching the arguments to the signatures, we give an error rather than attempting to guess what the developer meant by looking at stuff that is not in the signature, like the constraints. This is a good thing. We cannot know whether the developer (1) intended to call a worse method, or (2) did not understand that the arguments they chose cause the best method to violate a constraint. When faced with a situation where the developer’s intentions are unclear, the right thing for the C# compiler to do is to give an error.

    This is one of our core design principles; when we even give the appearance of weakening this principle (a la “var”) or actually do weaken this principle (a la “dynamic”) we get pushback like you wouldn’t believe. If you prefer a language where a core design principle is “do your best to guess at what the developer meant and don’t worry too much if you get it wrong and cause crashes or logic errors as a result”, then VB or JScript are possibly better language choices for you. Both approaches are reasonable; we design the C# language for people who want to be told when the compiler would have to guess what they meant.

    I’ve tried a dozen different ways to explain this and yet people keep on coming back to it. Evidently I am bad at explaining it, so I’m going to stop trying. — Eric

  99. Sam Freeman says:

    Also, cheers to Darren oakey – I agree with what he’s saying:

    "if you define the constraints to be part of the signature, and allow overloads that differ only on constraint – you still have a completely consistent, working model"

    In other words,

          static void Draw<T>(T t) where T : Square { }

          static void Draw<T>(T t) where T : Circle { }

    is not ambiguous and could indeed be very useful.  We may want to Draw the class of all things Square completely differently than the class of all things Circle.  If we want a catch-all that supersedes the non-generic (object) version, then simply add:

          static void Draw<T>(T t)

    In the absence of using generic constraints in the signature, it just becomes too awkward, if not impossible, to disambiguate the call.  Generic constraints would be a nice way of allowing for detailed specialization and would not introduce any static inconsistency if they were part of the method signature.

  100. Sam Freeman says:

    Eric,

    You say: "How does that work, unless the developer writing the callee is the same as the developer writing the caller? That is frequently not the case."

    But you could say the same thing about any overload.

    As far as: "When faced with a situation where the developer’s intentions are unclear, the right thing for the C# compiler to do is to give an error."

    I agree.  That’s why I’d like to see the generic constraints become a part of the signature so that the intentions would not be unclear.  In other words, the intentions of the developer are unclear precisely because the C# team chose to ignore generic constraints for purposes of overload resolution.

    I’m a huge fan of C++ because it allows for ‘var-like’ things via template specialization with zero "0" runtime overhead and zero type ambiguity.  I have very little use for scripting languages that try to guess what I mean — I’ve been down that road and I know the pitfalls.  So please don’t feel so discouraged – I get what you are saying:

    "the programmer writing the call site intends to call a particular method, and communicates this by selecting arguments which overload resolution will use to choose a particular matching signature."

    Everything you say is exactly right.  But, if you change the definition of what the "signature" is (to include generic constraints), then the method that the caller is selecting with arguments 1) changes, and 2) is still unambiguos.  So, the only argument here, is what the signature should be.

    BTW, I think C# rocks and I’ve used a lot of languages.

           — Sam

  101. paul c says:

    Good article cheers for that. Now i can sleep safely at nightly knowing my type arguments are being checked by my compiler … phew for that

  102. Cisjokey says:

    I have to stick with paul c.

    What are you guys discussing here? Im generly a big fan blog styled diskussions, but hey.. If you have anything like

    Foo.Bar(object object)

    and

    Foo.Bar(string)

    Pay attention, it will catch you… (Even if you are the nerd that knows how it gets resolved)

    What should

    void Foo<T>(T t) where T : Reptile { }

    do? Is this only a plain sample which makes no sense?

  103. Tahir says:

    “In this case, the spec is exactly the way we want it,” – Eric

    I like this piece. Eric, with all due respect, what matters here is not what YOU want, but what WE, the developers and primary users of the product (C# language) want. As you can see from this thread, the majority agrees that constraints have to be part of the signature and (slightly off-topic) that constraints have to be enhanced. There are other improvements that were proposed here, as well (Markus W.’s post).

    First off, this is not a representative sample. Second, the design of C# is not a democracy. And third, the spec is the way we want it because it is right, and no amount of people wanting it to be wrong is going to make the wrong thing right. The right thing to do, based on the design principles of C#, is to identify when the program is ambiguous and therefore likely to be wrong, so that you can fix it. The wrong thing to do is to guess that you meant a worse method and silently choose it, thereby introducing bugs. I don’t know why I have to keep making this point over and over again. — Eric 

    Now, we all understand budget and time constraints, you guys just can’t add features like that left and right – no sweat. But don’t tell us that it “is exactly the way we want it”, because that’s a terrible argument. There is very little doubt that the enhancements requested in this discussion and other places are needed – and when MS’s response is that, “we don’t think that’s necessary”, that’s a bad way of putting “we don’t care what you want, we’re too lazy (as a company) to develop it, now eat it”. It would be much more honest and nice to say that, “we can’t do it now, but will try to ASAP”.

    We care very very much about what customers want and need, and appreciate this feedback. We get proposed “enhancements” all the time that violate the fundamental design principles of the language in order to make narrow, rare scenarios like this one slightly more convenient, and we don’t do them because it’s a bad idea to spend our limited budget making features that work against our design principles and thereby make the language worse for the majority in order to increase convenience a minescule amount for a tiny minority. That’s not laziness, nor is it dishonesty, and frankly I resent the insinuation that my team is lazy and dishonest. Rather, that is being respectful of the needs of our millions of users. — Eric

  104. Brannon King says:

    "The right thing to do … is to identify when the program is ambiguous and therefore likely to be wrong, so that you can fix it. The wrong thing to do is to guess that you meant a worse method and silently choose it, thereby introducing bugs. I don’t know why I have to keep making this point over and over again. — Eric"

    It seems to me that the point of many statements here is that adding constraints to the resolver does not introduce bugs. And it’s not a matter of introducing bugs! It’s a matter of reduced functionality.

    My earlier point was that resolving methods by parameter footprints alone is insufficient to make extension methods work in a reasonable fashion. Extension methods should not have been added to the language with that limitation. You can’t have an extension method that uses IList<T>, etc. The language has already been extended beyond the point where it needs the constraints in the method resolver. True?

    "As I’ve said now over ten times in these comments: we assume that the programmer writing the call site intends to call a particular method, and communicates this by selecting arguments which overload resolution will use to choose a particular matching signature…– Eric"

    That’s a rash assumption, especially in math and geomtery libraries. In those cases I expect the best method for my current shape/matrix/number/etc to be called. Why would we make coders search through a vast array of overloads, chose the best one, and then call it manually through the use of casts? We somehow think this manual process and excess code reduces bugs? Hardly.

  105. Tahir says:

    Eric,

    Thanks for replying – I do appreciate your time, and please don’t find my remarks offensive – I didn’t mean to call your team lazy, that’s why I said “as a company” which is a different thing. Besides, C# is already a very functional and flexible language, thanks in no part to your work.

    You said that this discussion is not a representative sample, which is true, but combined with hundreds of other forum topics and MS Connect requests, etc., it may as well become one. The decision that the spec is right was made by your team, which is a group of people, but when there is a larger group of people who have a different opinion, then it’s not immediately clear that what a smaller group says is more correct than what a larger group says – and this, I believe, is exactly the case here. What you think is a tiny minority is not actually so tiny, because not all developers follow these blogs and post their opinion – only those, who care about making the language better. Big part of the “majority” that you are referring to doesn’t even know what generics are, and I don’t see how these changes will negatively affect the work of others.

    Now, on the technical side, the only thing stopping the code you quoted from compiling properly is the absence of constraints in the method signature. There must be a reason for that decision – and I couldn’t find that reason anywhere in this discussion. Basically, you kept saying that it’s not allowed because it’s not allowed, which doesn’t clarify things. You wrote:

    “And there’s the difference of opinion right there. To you it is obvious that the intention was not to call the illegal method. That is not obvious to me at all; coming to that conclusion requires that we accurately model the mental state of developers who have written a program where a perfect match is illegal. It’s hard to say what the intention of such a programmer is.” – Eric

    What is not obvious? Type constraints are there to communicate the “mental state” of the developer to the compiler.

    You’re conflating the mental state of the person writing the method with that of the person calling the method. Those are frequently two completely different people, working at different companies. — Eric

    In any case, I doubt you will change your mind even after couple dozen professional programmers telling you the spec is wrong. Just to finish this off, let me remind you of optional method arguments, how it was originally considered bad and “not explicit” enough, and how programmers wrote thousands of useless methods to overcome that stupid limitation, only to make all that work redundant in C# 4.0. The reason was that optional arguments were never bad; it’s just that your team (and maybe even yourself) had THOUGHT they were bad and then realized they weren’t, or it was too much work at the time, and you decided to come back to it and do it now. In both cases, it adds more work to our plates and your plates too – in the future, when in C# 6.0 or whatever MS suddenly realizes that constraints do belong to signatures and all the extra work that was done in the process becomes redundant, too. No big deal, but a deal nonetheless.

    That’s an interesting example to contrast against the one under discussion. I think pretty much everyone on the design team agreed that named and optional arguments are vexing. They make the task of overload resolution more difficult, they introduce a number of new points of failure and confusion into the language, and they encourage bad-code-smell designs which have an excessive number of formal parameters to methods. Those are all points against, and good justification for not doing the feature for the first three versions. Points for are: we’ve spent ten+ years trying to get good interop with legacy COM object models, and made very little headway on this problem from the “convince the guys who proffer up those object models to make them more amenable to C# programmers” side of things. I still think that optional arguments are a bad idea for C# in their own right, but if we cannot move a large body of programmers towards the language due to interop concerns then we’ll do the work to move the language towards those customers. (We considered restricting named and optional parameters to calls which we knew were on legacy COM objects, but the overwhelming pushback we got from the MVPs was “either do the feature completely, or don’t do it at all.”)

    Design is always the art of finding good compromises amongst conflicting goals; in this particular case, the “reach” goal of enabling interop with legacy object models trumped the “purity” goal of avoiding all the problems inherent with named and optional arguments.

    By contrast, the issue we’ve been discussing here is, frankly, minescule. There are tens of millions of programmers who use legacy COM objects and who are genuinely prevented from using C# by the C# 3 semantics around interop with dynamic COM objects and PIA types; we seek to improve all their lives with C# 4. I can only imagine that the number of programmers who are genuinely blocked by the fact that generic constraints are not considered when checking signature matching is tiny. Surely the workaround is merely the insertion of the appropriate cast to shut up the compiler, and life goes on. I really don’t see why this reasonable, albeit debatable, design decision has sparked so much comment. — Eric

    Thanks for your time, and good luck.

  106. Tahir says:

    “You’re conflating the mental state of the person writing the method with that of the person calling the method. Those are frequently two completely different people, working at different companies.” — Eric

    That’s exactly why I mentioned abstraction.

    The developer who writes the methods should be worried about correct resolution of the overloaded methods. He should ensure that Reptiles, Mammals, etc. are handled properly by using proper parameter types (or generic type constraints).

    The developers who consume these methods shouldn’t know about that; as far as they are concerned, all that needs to be written is a call to Foo, which should automatically resolve to the best overload.

    And it does. If the best overload based on the arguments provided is invalid, then they should be told about that. — Eric

    “That’s an interesting example to contrast against the one under discussion. I think pretty much everyone on the design team agreed that named and optional arguments are vexing. They make the task of overload resolution more difficult, they introduce a number of new points of failure and confusion into the language, and they encourage bad-code-smell designs which have an excessive number of formal parameters to methods.” – Eric

    And again, I disagree. While it does make overload resolution trickier, it doesn’t necessarily translate into more failure points. What happens usually is this:

    Foo(int a, int b) { … }

    Foo(int a) { Foo(a, 10); }

    Now, by introducing Foo(int a, int b = 10) { … }, overload resolution has to deal with the same thing, but written differently. It makes the job of the compiler a little more difficult, but that’s not a failure point because all of this is resolved during compilation anyways.

    Absolutely it causes all kinds of new failure modes. Now parameter names effectively become a part of the signature, when they were not before. Renaming a formal parameter in a base class can become a breaking change; that’s new. Calling a virtual method via an instance of a base class can choose a different overload than calling it via the derived class based on differences in parameter names rather than differences in argument types; that’s new. I could list you half a dozen ways that overload resolution now breaks horribly that never happened before, just because of named arguments. Each one of these is a potential source of painful bugs. Going with this was not an easy choice; all our users will pay the price for it, unfortunately, not just the users who do interop with legacy COM objects. — Eric

  107. Tahir says:

    “If the best overload based on the arguments provided is invalid, then they should be told about that.” — Eric

    I think myself and others are missing something easy here that you weren’t able to communicate to us – I still fail to see why the determination of which overload is best can’t consider constraints.

    Because then it sometimes rejects methods that are clearly better and picks methods that are clearly worse. I’ve already given examples of such. Your argument is “if we call the tail a leg then a sheep has five legs”. I’m with Lincoln; I say that a sheep only has four legs no matter what you call the tail. If we call a worse method “better” that doesn’t magically make it actually better; it magically makes the compiler generate a program that the developer did not intend. When a constraint is violated the developer has probably made a mistake. In a situation where it is ambiguous whether the developer has made a mistake or has done it intentionally, we ask you to disambiguate that for us. That’s a good thing.

    I don’t see why this particular rare, unusual issue that is easily worked around in real code has caused so much comment. I could give you other examples of places in the language where we are faced with an ambiguity and choose to alert the developer rather than guess that they meant something else, examples where the scenarios are far more likely in real code than this contrived example.

    — Eric 

    “Renaming a formal parameter in a base class can become a breaking change; that’s new. Calling a virtual method via an instance of a base class can choose a different overload than calling it via the derived class based on differences in parameter names rather than differences in argument types; that’s new.” — Eric

    I was under the impression that where method is virtual, its signature can’t change – so if the parameter names change and they are part of the signature, inherited classes’ methods shouldn’t compile. Having established this, why would there be a discrepancy in overload resolution? (assuming there are no new methods introduced in the child class) Also, all of these problems are caused by named parameters; optional parameters in C++ fashion wouldn’t have caused any of these problems.

    Parameter names are not now part of the signature, nor have they ever been part of the signature, so you are reasoning from a false premise. Optional parameters cause numerous problems of their own; my comment was not intended to be construed as an exhaustive list of every single problem these new features cause. — Eric

  108. Markus W. says:

    In C++ SFINAE is a golden principle and approved as a GoodThing (TM).

    To clarify, this is the name of the feature of C++ where template substitution that produces an invalid result is not an error. — Eric 

    I’d like to know why for C# generics things have to be the other way round.

    Markus

    In C#, failure of method type inference to infer something isn’t an error. Method type inference inferring something that is the best match, but doesn’t meet constraints is an error. I’ve explained a dozen times why it is an error: because a program with that property is probably a mistake, and should be brought to the user’s attention. This is a better policy for C# than muddling on through and hoping for the best while choosing a worse candidate. It doesn’t *have* to be that way. We *choose* for it to be that way because that’s the better choice for C#. — Eric

  109. Markus W. says:

    Eric writes:

    > It doesn’t *have* to be that way.

    Ahh!

    > We *choose* for it to be that way because that’s the better choice for C#.

    “better choice” is exactly where I cannot follow. My point is that in C++ the failing template instatiation will remove a template function from the overload set (which is the basic technology behine boost::enable_if). I used C++ templates to do really fancy stuff and I was looking forward to C# generics to give me the same power in porgramming methodology. To me the issue described here *is* a showstopper. Of course the C# language design can be as arbitrary as can be (and differ from C++), unless it hinders me to do what I want to do. I feel like this is the case here (and with C# generics all along). Without the rules described above, generic constraints could have helped around some issues like e.g. the missing specialization feature.

    Also you say “The best possible choice is not viable; the correct behaviour is to tell you that, rather than blithely choose the second-best choice and hope for the best.”

    I disagree completely. How can you say it is not viable? If I am the author of my overload set I could have used the inexitent “constraint is part of the signature” rule to do fancy things here. I do NOT consider the second-best choice to be second-best. Why hindering expressibility by cutting off features in favour to an error message that *might* probably catch an error at compile time that never passes a unit test? Sorry to say so: I agree that you might decide the language to be as it is now, but I strongly disagree with this beeing a good choice.

    Markus

    I am opposed to “fancy things”. I like it when C# is used to make boring, sensible line-of-business code.

    Generic types are to make parameterized types, like sorted dictionaries. Generic types are not intended for, and therefore not designed for, full-on metaprogramming. If what you want is a template-based metaprogramming system, and not having one is a showstopper, then C# is not the right language for you. We aim to be the right language for a lot of people, and I would like it if some day we did have a metaprogramming system. Generic types aren’t that. — Eric

  110. Markus W. says:

    Eric said: “I can only imagine that the number of programmers who are genuinely blocked by the fact that generic constraints are not considered when checking signature matching is tiny.”

    Maybe this is due to the fact that most programmers trying out C# come from languages where generics indeed are unknown or underdeveloped. I am a C++ programmer (many of them out there) trying to get along with C# (and C++/CLI). Let me tell you that I got disappointed within a rather short period of time. IMHO the combination of templates with multiple inheritance is the most important feature in C++ and enables us to write elegant, highly expressive code with an extreme level of abstraction (see boost::spirit or boost::proto for example). Now taking a glance at C#, both features are somehow underdeveloped. I would not even try to build something as cool as boost::spirit in C#. One of the reasons in this blog. Doesn’t that make you feel uncomfortable?

    Nope, that makes me feel good. Elegant I like. Expressive I like. Extreme level of abstraction I don’t like. I like plain boring straightforward unsurprising code that fulfills a clear business purpose.

    I’m a professional language designer with 18 years experience programming in C++, and I still cannot make heads nor tails of most C++ template code. The level of abstraction is frequently too high for me to grasp. And based on the few godawful bugs I’ve had to fix in template-heavy code over the years, it was frequently too high for its authors to grasp as well.

    I prefer a simpler, less powerful system that has a clear purpose: easing the construction of parameterized types like container types.  — Eric

  111. Markus W. says:

    I admit that in modern C++ the template system is somewhat "abused" to do all the fancy things you are opposed to. The code is ugly and sometimes unreadable. Of course there are better ways to design a language that supports all those features. A great chance for C# to beat ’em all!

    OTOH what makes me feel happy with C++ is the fact that the basic idea of its language design is not to put any restrictions on the programming paradigm. It is exactly this attitude that leads to a sense of freedom and a "Can-Do-That", of course disregarding the pain it may take to fulfill the task, but you can. Example: LINQ is cool. Take boost::proto and half a year of concentrated work and the same thing works smoothly in C++. You can do that. My own experience with C# is exactly the opposite. Every week I run into a "Can’t-Do-That" (like missing operator=) or a caveat that is hurting. This is where your aim to keep it simple leads to the opposite: weird looking workarounds that make the code complex and far from being clear and concise.

    Back to the original problem: IMHO the deliberately chosen rules here offer a little advantage to probably catch a subtle error while at the same time hinder a plethora of useful applications. To me this feels ike the damage done by the design decision outweighs the benefit by a factor of 10.

    Also what I still do not get: If you "like plain boring straightforward unsurprising code", then why such a counter-intuitive behaviour?

  112. Markus W. says:

    Slightly OT: Eric says:

    > I prefer a simpler, less powerful system that has a clear purpose: easing the construction of parameterized types like container types.

    I tried to write my own container in C# and was astonished about the lack of features in C# generics. When I was a bloody beginner in C++, specialization and partial specialization were intuitve and logical to me. I guess these two features may give C# a boost. What do you think?

  113. Brant says:

    It seems that the generics problem is not so much a bug in the compiler as it is a Legacy .NET 1.0 fragment.  .NET 1.0 did not use generics, and as .NET 2.0 is based on 1.0 I imagine it kept the same method resolution because if a new type of overloading was added it would probably break just about everything. Also I see generic type constraints as just a tool to help us as coders, not to help the compiler or runtime, the speed of C# would probably be greatly affected if several (object is Type) operations needed to be called upon every method call, which is what generic constraint overloading would require.  So altho generic constraing overloading would be a nice feature for coders, it would probably degrade the entire user experience of C#.

  114. Maico says:

     Jonathan said:

    It seems to me that this is indeed a compiler bug, and what you have shown is that it results from a bug in the spec.

    No, a bug in the compiler would be an implementation that doesn’t match the spec. A bug in the spec is a spec which doesn’t match the desires of the language designers. In this case the implementation, the spec, and the language designers all agree. Now, you might be of the opinion that this was a lousy design decision, but it is not an error. — Eric

    It’s a language designers bug. 🙂

  115. McKay says:

    So, I agree with Eric. Given the foo declarations above

    Foo(new Giraffe());

    Foo<Giraffe>(new Giraffe());

    These two lines of code need to do exactly the same thing*. Anything else is weird.

    *unless there’s a method (Foo(Giraffe), because that’s the only thing that is a closer match to Foo(new Giraffe()) than Foo<T>(T).

    I think that if people don’t see this, they’re missing how C# works.

    They always have the ability to write their method as

    void Foo(Reptile r)

    instead of

    void Foo<T>(T t) where T : Reptile

    When people say "well, I read

    void Foo<T>(T t) where T : Reptile

    as

    void Foo(Reptile t)

    in my head"

    They’re oversimplifying things, because they aren’t the same. If the person wanted void Foo(Reptile t) they should have written that. Maybe that’s the bug. void Foo<T>(T t) is different.

  116. TheToid says:

    Ok, so its definitely not a BUG, but I think its BAD compiler design, the compiler should use ALL NECESSARY INFORMATION when doing overloading inferencing, if this means that the constraints SHOULD be part of the method signature then so be it. If the compiler was to use the constraints it could SCORE each method based on how many levels away a match is from its descendant, and an overload method call IMHO should ALWAYS use a compatible NON-GENERIC method BEFORE any Generic Method.

    Personally I love generics when it comes to types on a class, but I refuse to use generics for individual methods, its bad code design and messy IMO.

  117. Paulo Zemek says:

    "No, there is one non-generic method called foo, and there is a pattern for generating infinitely many additional methods called Foo, the pattern is called Foo<T>."

    I think the main problem is here.

    If you don’t consider constraints, you are right. You have a pattern for generating as many methods as needed. But, if you consider the constraint, Foo<T> is not able to generate a method for Giraffe.

    See the difference?

    Foo(one parameter) is one thing.

    Foo(Reptile or a sub-class of Repite) is another thing.

    Some said: It is like

    Foo(Animal…)

    and Foo(Reptile…)

    Ok… it is not Foo(Repitle)… but it will only generate methods for Repite or sub-classes of repite… so, I can assume the "Foo(Repitle)" as the first tought is right. Instead of considering T to be any type (so it looks like starting from System.Object), what will be lost in considering constraints? I can only see compilation times to change… I can’t see "guessing" or any other thing.

    Also, I always wanted to:

    Create a generic class, without constraints

    And implement a method having a constraint for such type.

    For example:

    class MyClass<T>

    {

     Method1(T…)

     Method2(T) where T: struct

    }

    So Method2 will only exist for value-types, but the same class will exist for value and reference types.

  118. Paul says:

    It seems to me that C# is picking up all VB’s bad habits.

    I never knew generic types in methods could be infered from the parameters. Personally I’m going to put it out of my mind again. As for preventing the compile. IMHO its correct to do so.

  119. configurator says:

    I know this thread is almost 2 years old, but this needs to be said: everyone who objects to this feature has already responded. But some of us, including me, think you've made the right choice here, and giving an error is The Right Thing™ for C# to do here.

    C# is a great language with some design principles that make it as solid as it is. One of the most important one is: if the developer has made a mistake, let them know. This is one of the strongest features I've seen in a language, and one of the main reasons I'm an avid C# supporter. Let the functional pragmatists laugh at me. Given a choice, I'll still use this language for line-of-business applications, because it makes my life easier.

  120. ruud@jorasolutions.nl says:

    I just run into a problem which demonstrates a (serious) downside of not having constraints as part of the signature. Although this thread is by now rather old, it feels like worth pointing out this case:

       class A { }

       class B { }

       static class AHelper

       {

           public static IQueryable<T> MySelection<T>(this IQueryable<T> aQuery)

               where T : A

           {

               return aQuery.Where(a => ….);

           }

       }

       static class BHelper

       {

           public static IQueryable<T> MySelection<T>(this IQueryable<T> bQuery)

              where T : B

           {

               return bQuery.Where(a => ….);

           }

       }

       void Test()

       {

            IQueryable<A> query

            query.MySelection();

       }

    The second line of the Test() method yields two errors: one about being ambiguious between the two extensions, the second about A not being a valid type parameter for the BHelper extension.

    Keep up the good work.

    Regards, Ruud

  121. Sam says:

    It seems obvious to me that there is a disconnect  between what you were trying to explain here and what people were understanding. I think the general consensus based on the responses is that people expect that constraints *should* be part of the signature, not necessarily that the overload resolution algorithm is somehow wrong.