41

It is possible in C# to add variance annotation to type parameter, constrained to be value type:

interface IFoo<in T> where T : struct
{
  void Boo(T x);
}

Why is this allowed by compiler if variance annotation makes completely no sense in a such situation?

Massimiliano
  • 16,770
  • 10
  • 69
  • 112
controlflow
  • 6,667
  • 1
  • 31
  • 55
  • 1
    Does the compiler allow it without the interface? Remember interfaces are reference types - and when you have a reference to a struct (as an interface) it is automatically boxed... – MattDavey Feb 19 '12 at 21:16
  • 1
    @MattDavey, without interface constraint it compiles well too. Covariant/contravariant conversions requires uniform representation of source and target types and `IFoo` and `IFoo` are actually represented differently, so there is not conversion exists. – controlflow Feb 19 '12 at 21:22
  • 1
    Ok, sorry for the stupid question, but can somebody explain to me why in the code above the variance annotation makes no sense? – Tudor Feb 19 '12 at 21:35
  • 1
    @Tudor, just try to create the class that implements `IFoo` interface and try to use contravariant conversion with it. – controlflow Feb 19 '12 at 21:37
  • I guess this is one of those questions which gets answered as: "To uniformly define the language". There are more constructs that don't make sense but are handled uniformly. Maybe 'if ();' is allowed too, doesn't make sense either. – M Platvoet Feb 19 '12 at 21:45
  • 5
    @Tudor: It is not a stupid question. Covariant and contravariant conversions are only allowed if the type arguments are both reference types. That is, you can make a variant conversion between `I` and `I`, but not between `I` and `I`. Since this interface says both "I want variance" and "but I only want value types", it doesn't make any sense; the variance feature will never be used. – Eric Lippert Feb 20 '12 at 01:49
  • wow - OP prompting new features in a major compiler - that should be a gold badge :D – MattDavey Feb 20 '12 at 10:45

2 Answers2

37

Why this is allowed by compiler since variance annotation make completely no sense in a such situation?

It's allowed by the compiler because I never even considered that someone might try to do that when I added the variance rules to the C# 4.0 compiler.

Compiler warnings and errors are features, and in order for a feature to be implemented, it has to, at a bare minimum, be thought of at some point before you ship your compiler. I failed to do so, and therefore never had the opportunity to even debate whether there ought to be a warning for such a situation.

Now that you've brought it to my attention, the question is: should it be a feature? Should the compiler produce a warning (or error) for this case?

That's a judgment call. A number of things we'd consider are:

  • Is the code the sort of thing someone might type in thinking it does something sensible? One hopes not; one hopes that the developer who knows enough about the type system to make an interface variant also knows that variance only works on reference types. But maybe there are developers out there who might type this in thinking that it will work. It doesn't seem beyond plausibility at least. It's not clearly contrived.

  • Is the code clearly wrong? Yes, it probably is. It seems very unlikely that someone deliberately wants to write an interface that looks variant but in fact is not.

And so on.

I'll have to give it more thought, but at first glance it looks like this actually might be a decent warning to add to the compiler. I'll talk it over with the team and we'll consider adding it to the Roslyn version.

Thanks for the idea!

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Ha! My first thought when I read the question was "probably nobody thought about it, let's wait and see what Eric has to say". Now I wish I'd taken the time to add a comment :) I'd add that I frequently find myself using covariance on a generic type parameter and getting warnings; I'm still at the stage where it takes me 30 or 60 seconds before I remember that I need to add the `class` constraint for that. So a more-specific message on the compiler error ("did you forget to add the class constraint?" or the like) would certainly help me, and probably others as well. – phoog Feb 21 '12 at 15:07
  • Eric, you're always honest! Besides being knowledgeable. :) – nawfal Jul 07 '14 at 07:23
2

It is allowed simply because it is legal code. There is absolutely no harm in it. Yes, you can not use contravariant conversion, but I fail to see the problem. Nothing in the code will actually be misleading or hide some twisted gotcha.

I simply think the compiler doesn't check if T is a value type or a reference type when checking for variance validity. It stands to reason that the C# team assumed that anyone using generic interface variance would know that doing so with value types is pointless and in in any case has no secondary effects.

InBetween
  • 32,319
  • 3
  • 50
  • 90