In the example above, didn’t the programmer mean IEnumberable<Animal>?

Or, perhaps IEnumerable<T> where T : Giraffe, Turtle?

But, assuming this is a more legitimate case of two IEnumerable<> types, it seems the compiler should support this. (Not a compile time error.)

The LHS is requesting (in the example) a very specific interface. The IEnumerable<Turtle> interface. At compile time, it seems plausible that this type could be deduced. In fact, you should be able to follow this up the heirarchy to IEnumerable<Animal> and so on.

Additionally, if it were not for backwards compatibility, I’m not sure if it’s necessary to allow the implementation of a covariant interface for two Ts that share a common base type. Too confusing, too hard to guess what happens, and prone to cause runtime-errors. Maybe a warning would be a good idea: "CSxxxx – Don’t implement covariant interfaces that way unless you _really_ know what you’re doing." On the other hand, while only true for the special case of IEnumerable<T>: if you implement IEnumerable<T> for two different Ts, you still have to implement the non-generic IEnumerable. If that doesn’t tip you off, you might as well accept the punishment 😉

And yes, your blog is fascinating enough that I care to read and comment although your policy of not answering most of my comments has not changed so far. It could be so much better though.

The compiler should in no case choose one over the other -> compile time error.

The more specialiced case would be, what if there’s an implicit and an explicit interface implemenation?

class C : IEnumerable<Giraffe>, IEnumerable<Turtle> {

IEnumerator<Giraffe> GetEnumerator() {

yield return new Giraffe();

}

IEnumerator<Turtle> IEnumerable<Turtle>.GetEnumerator() {

yield return new Turtle();

}

// [etc.]

}

class Program {

static void Main() {

IEnumerable<Animal> animals = new C();

Console.WriteLine(animals.First().GetType().ToString());

}

}

Should the compiler choose the implicit implementation or also cause a compiler error?

Another solution comes into my mind:

What if the compiler would issue an error because the class implements two "overlapping" covariant interfaces? The two covariant interfaces IEnumerable<Giraffe> and IEnumerable<Turtle> should maybe have some kind of equivalence relation in the context of implementing them by a class.

Additional question (I guess it’s really the same question as the vtable implementation): Is an assignment of an IEnumerable<Giraffe> to an IEnumerable<Animal> variable statically verifyable, i.e. is it just copying a DWORD at runtime, or do you have to check or even convert the assignment?

Either way, I’d argue that implementing IEnumerable<T> for Giraffe AND Turtle should break covariance. I noted that the CLR currently chooses option 3 (first interface implemented), and I really think this is dangerous. I know I’m asking a lot for breaking changes, this looks wrong. I say discourage these implementations (using warnings), and break covariance if the programmer insists.

It can’t be compile time error because of the philosophy that adding an interface to a class in a library should never break client code.

Also you can’t choose between giraffes and turtles neither at runtime or compile time for the very same reason. An library implementer might change the order of interface declarations and not preserve it.

The only solution I see is to allow only one ‘implicit’ interface implementation for a covariant interface and the others should be ‘explicit’. Why? Because both IEnumerable<Giraffe> and IEnumerable<Turtle> are the same as IEnumerable<Animal> when T is covariant, basically implementing IEnumerable<Animal> twice, with the exception that they carry extra type info that can be used to skip casts.

{

Other solution might be not to mark IEnumerable<T+> as covariant but to mark it in the implemented class

class C : IEnumerable<Giraffe+>, IEnumerable<Turtle>

where IEnumerable<Giraffe+> is now covariant? (uh those terms make my head spin)

It should be a compile time error. Because when you consider code like

IEnumerable<Animal> animals = c;

multiple paths exist for the conversion to succeed. Compiler should die the death of Buridan’s ass, since there is no motivation to choose one conversion over the other.

This problem readily manifests itself in C++ where multiply inheriting a class is allowed, the famous "diamond" hierarchies of inheritance. In CLR, I think it is the only closest feature to diamond hierarchies.

Without further language enhancements, in the face of non(-obvious)-determinism, I say…

Compile time error.

Except it is possible to image a scenario where such a setup would be useful. Consider the enumerable to be a producer of some sort of "Item"s. As a handy feature, it can directly produce the appropriately subclassed "SmallItem" or "ScalableItem". Such a producer might implement IEnumerable<SmallItem> and IEnumerable<ScalableItem> such that that the consumer can get the appropriately formed items he needs easily.

Currently, a software doing something like that would do so precisely to do a poor-mans covariance, and is trying to be useful while at it. A feature which saves the consumer effort today, (by allowing the IEnumerable client to just pick what’s needed), would turn into a confusing situation for in this version – why can I do covariance casting on "almost" all interface implementations, but not this one?

This situation, in essence, already exists today, and the solution there is the right one.

If you want to implement IEnumerable<a> and IEnumerable<b>, what do you do in a foreach? You iterate over the IEnumerable – i.e. you force the interface implementor to choose.

Ideally, if you implement two interfaces which are potentially covariant, you should at the least be forced to prioritize (in some fashion), and at worst to implement the border case explicitly (nasty, not preferred). Of course, that means that in a hypothetical future CLR marking IEnumerable<T> covariant would be a (massively) breaking change… that’s why I’m saying ideally, since that’s probably not reasonable.

Is it supposed to return the first _implemented_ type? That seems a little ridiculous, but that is is up to the definition of the method.

Besides the assignability of C to IEnumerable<Animal> I do not think that this example has any relevance on variance. The fact that C simultaneously implements IEnumerable<Giraffe> and IEnumerable<Turtle> seems to be a poor design, but from the language point of view it is certainly legal regardless of variance. There may even be appropriate uses for it (I do not know).

Thus, I will have to choose "6) Other, please specify": clean compile, no error, warning, or run-time exception. Depending on the definition of First, either Giraffe or Turtle would be acceptable. If you can explain the definition of First, I will try to give a better answer.

What Peter Ritchie said. You’re providing two different IEnumerable<Animal> implementations, so the user has to specify which one they want (by casting the C to IEnumerable<T> for T in {Giraffe, Turtle}).

I wonder if it would be possible to return a "multi-type" variable? Ie// one that is either a Giraffe or a Turtle, but never a "Lion" or an "Alligator".

To me, at least, this code is trying to tell you that the container can hold only Giraffes and Turtles and nothing else from the set of Animals (perhaps because storing Giraffes and Lions in the same container leads to bad results). Enumerating through the container should get a single aggregate set of both Turtles and Giraffes, depending upon what was stored in there. Trying to store a Lion in that code should fail at compile time but adding either Turtles or Giraffes should be just fine.

In that conceptual model, the "First().GetType()" call should return a hybrid type of "Giraffe" | "Turtle" in the generic sense, but a specific "Giraffe" or "Turtle" in the specific case depending upon the type stored in the first element.

Is there a better way to express this programatic desire? Currently, the only way to put N siblings together is to either implement a seperate container for each, to include the base class or to implement some middle "GirraffeAndTurtle" class which inherits from "Animal" and from which both Turlte and Giraffe are derived. It would be nice to have something clearer.

James: if there were a "multi-type" return, what would it mean to call its "Reproduce" method, considering the Giraffe is a mammal that births its young and the turtle is a reptile that lays eggs. At some point you need to tell the compiler which of the two types you want to deal with.

I assume it is a (pseudo) extension method, but exactly what is it suppose to do?

I briefly looked for some documentation but to no avail.

Jon Skeet wrote:

> First extends IEnumerable<T> and returns a T – the first one in the sequence.

I still do not understand. How would First, a method, extend the type IEnumerable<T>? And if First is a type, then how is it going to return a T? In particular, please expand on "it returns a T – the first one in the sequence". What sequence? The only sequence here is the order of implemented interfaces. Are you suggesting First uses reflection to look at the order of implemented interfaces and returns the first one? That seems rather foolish, but it is certainly quite possible and should not be a compiler error. Or would it call GetEnumerator() and then get the first element? In which case, animals would need to be upcasted to the desired interface to bind to the appropriate GetEnumerator(). This has nothing to do with variance the current rules apply.

Like Ben, without more information, it is difficult to judge. However, depending on the definition of First, either Giraffe or Turtle would be OK. I would not expect a warning, error, or exception.

Considering Eric’s clarification and new example, error for both cases. More specifically, CS1640 seems appropriate. Why? Because it is the same issue as in existing implementations and has nothing to do with variance. Don’t over think it. The only variance issue here is the acceptability of assigning C to to IEnumerable<Animal>.

However, upon reaching line 3 (foreach), animals, which points to a C instance, implements IEnumerable<Giraffe> and IEnumerable<Turtle>, the same interface multiple times and should thus produce CS1640.

The difference though is that in your example, C does in fact implement IEnumerable<int>. Thus, it knows exactly which one to bind to. Changing e to C e = new C() will of course produce CS1640.

> because you’re converting to the IEnumerable<Animal> type first, the compiler will know which

> GetEnumerator to use.

It does? And which one would that be? There is no IEnumerable<Animal>.GetEnumerator() that returns an IEnumerator<Animal>. It can only return an IEnumerator<Giraffe> or IEnumerator<Turtle>, both of which may be treated as an IEnumerator<Animal> and thus the ambiguituy: CS1640.

Ben, the example code was pulled from the documentation for CS1640 and slightly modified. This is the original code:

public class C : IEnumerable, IEnumerable<int>, IEnumerable<string>

{

IEnumerator<int> IEnumerable<int>.GetEnumerator()

{

yield break;

}

IEnumerator<string> IEnumerable<string>.GetEnumerator()

{

yield break;

}

IEnumerator IEnumerable.GetEnumerator()

{

return (IEnumerator)((IEnumerable<string>)this).GetEnumerator();

}

}

public class Test

{

public static int Main()

{

foreach (int i in new C()){} // CS1640

// Try specifing the type of IEnumerable<T>

// foreach (int i in (IEnumerable<int>)new C()){}

return 1;

}

}

In Eric’s example, if he first converts to a IEnumerable<Animal> object, that object must have an IEnumerable<Animal> GetEnumerator() method so foreach knows exactly what GetEnumerator() to use, just as it knows in the IEnumerable<int>/IEnumerable<string> example because I forced it to use the IEnumerable<int> interface. If you don’t tell it what type of IEnumerable<T> to use, yes, the compiler thankfully won’t make the decision for you and spits out CS1640; but that’s not the case the Eric presented.

> There is no IEnumerable<Animal>.GetEnumerator() that returns an IEnumerator<Animal>. It can only return an IEnumerator<Giraffe> or IEnumerator<Turtle>, both of which may be treated as an IEnumerator<Animal> and thus the ambiguituy: CS1640.

OK, but how does the _compiler_ know that? Suppose I split the code into three assemblies:

I was thinking that notationally what you would get would be a set of operations common to every instance in the type return set. So if we constrain the output to be of type either turtle or giraffe and there is a method signature called reproduce that returns something common to both turtles and giraffes (perhaps, something in the <giraffe | turtle> set) then it would be ok. I was thinking of "weak duck typing", to put a made-up conceptual phrase on it. Ie//

gt.RunAwayFromPredator(Predator p); // Success. Both Turtle and Giraffe implement the run away method.

Another way to think of it would be automatic base-classing, where you’d get a duck-typed base class from the compiler that contained the set of operations common to both giraffes and turtles.

And remember, the underlying object would still be either a giraffe or a turtle, with the associated memory layout. All you’re doing notationally in my proposal is allowing the compiler to accept either one where it makes sense. The compiler would still have to keep the set of types around and resolve whether any operations on the "multi-typed" type.

Is there no way for the compiler to determine the exact type that something points at?

If not, then it may need to be a run-time error.

However, before that, in that case, it would fail when it looks for and can not find IEnumerator<Animal> IEnumerable<Animal>.GetEnumerator() in animals (of type IEnumerable<Animal>, but really pointing to C). That fact that C can also provide a IEnumerator<Giraffe> and IEnumerator<Turtle> which could pass as an IEnumerator<Animal> is immaterial if the compiler can not determine that animals is really an instance of C. Again, this would be a compile-time error, but not due to variance but rather because the compile can not determine that animals (IEnumerator<Animal>) is really a C instance.

It would be a terrible idea for C# to depend on the order of interfaces in the "inheritance list". This would be like depending on the order attributes are applied. I would be shocked if it weren’t a rule for C# design to avoid making ordering in such cases matter. There’s just too much room for error.

The type-casting logic needs to take into account the diamond problem and raise a compile-time error when possible, otherwise a run-time exception. I see no reasonable way for the compiler to know how to choose IEnumerable<Turtle> over IEnumerable<Giraffe>. If the author of the class wants to support IEnumerable<Animal>, he/she should implement it (I would say explicitly, but that has another meaning in C#).

Now, would it be reasonable to produce a compilation warning about possible diamond hierarchies?

Yes, the problem here IS in covariance. I picked IEnumerable<T> as just one example, but you are concentrating solely on the semantics of IEnumerable. How about if I pick some completely different interface:

Why is implementing the same interface instantiated with two different sets of type arguments a bad programming practice? If a Frob can be compared to a Frib or a Frub then why shouldn’t class Frob : IComparable<Frib>, IComparable<Frub> be perfectly legal?

The real question is about the nature of covariant interfaces: does the object bear the burden of providing the full spectrum or are an object’s interface definitions pulling double-duty? If the invariance is little more than shorthand for additional interface implementation requirements, then the class has to disambiguate IFoo<Animal> just to compile. If the interface itself is making the guarantees, then Bar has two distinct IFoo<Animal> implementations, but neither should be directly accessible.

In the former case, it’s Bar’s job to provide an unambiguous IFoo<Animal> implementation. Unless the covariance guarantee is simply weak and translates to a runtime exception.

In the latter case, it’s the runtime’s job to find the best match and detect ambiguities:

IFoo<Animal> f = new Bar(); // runtime error

IFoo<Mammal> m = new Bar(); // Get returns an Animal which is a Giraffe

IFoo<Animal> g = new Bar() as IFoo<Giraffe>; // Get returns an Animal which is a Giraffe

IFoo<Animal> t = new Bar() as IFoo<Turtle>; // Get returns an Animal which is a Turtle

The first line is statically ambiguous, with two legal-but-different conversions to IFoo<Animal> (you can go via IFoo<Giraffe> and via IFoo<Turtle>, with no way to choose). Static ambiguity should (obviously) yield a compile-time error. To resolve it you should have to choose a path, i.e. IFoo<Animal> f = (IFoo<Giraffe>)(new Bar()); to enumerate in the Giraffe style or IFoo<Animal> f = (IFoo<Turtle>)(new Bar()); to enumerate in the Turtle style.

For the similar but different situation:

"

object o = new Bar();

IFoo<Animal> f = (IFoo<Animal>)o;

Console.WriteLine(f.Get().GetType().ToString());"

Unfortunately we can’t make the first line ambiguous (there’s only one path back to object bceause there’s no multiple inheritance–if we had instead multiply inherited ABCs (which would extend object) instead of interfaces then the static ambiguity would return and be detectable). So instead we make the second line ambiguous, at runtime. It should throw an exception (AmbiguousCastException, say) that is extended from (but different to) InvalidCastException.

It appears that the very first line is itself inherently ambiguous. (That’s your point – right?) IEnumerable<Giraffe> implies one implicit conversion to IEnumerable<Animal>, and IEnumerable<Turtle> implies another (very different) implicit conversion to IEnumerable<Animal>. Thus, the definition of class C itself should result in a compile-time error, unless the developer provides some form of disambiguation.

is workable, and appears to provide a sufficient means of disambiguation. Therefore, it shouldn’t be mandatory that C implement IEnumerable<Animal>.

It appears to me that making generic IEnumerable covariant is not really a breaking change because code that tried to convert C to IEnumerable<Animal> was already illegal. OTOH, once IEnumerable becomes covariant, adding a new implementation of IEnumerable<T> (for a specific T) to almost any class will typically break existing code that performs a conversion to IEnumerable<object>.

I wonder how C# and the CLR would handle code like the following–now and after adding variance: