Interface conflict resolution in C# - c#

This is a spin-off question based on Eric Lippert's answer on this question.
I would like to know why the C# language is designed not being able to detect the correct interface member in the following specific case. I am not looking on feedback whether designing a class this way is considered best practice.
class Turtle { }
class Giraffe { }
class Ark : IEnumerable<Turtle>, IEnumerable<Giraffe>
{
public IEnumerator<Turtle> GetEnumerator()
{
yield break;
}
// explicit interface member 'IEnumerable.GetEnumerator'
IEnumerator IEnumerable.GetEnumerator()
{
yield break;
}
// explicit interface member 'IEnumerable<Giraffe>.GetEnumerator'
IEnumerator<Giraffe> IEnumerable<Giraffe>.GetEnumerator()
{
yield break;
}
}
In the code above, Ark has 3 conflicting implementation of GetEnumerator(). This conflict is resolved by treating IEnumerator<Turtle>'s implementation as default, and requiring specific casts for both others.
Retrieving the enumerators works like a charm:
var ark = new Ark();
var e1 = ((IEnumerable<Turtle>)ark).GetEnumerator(); // turtle
var e2 = ((IEnumerable<Giraffe>)ark).GetEnumerator(); // giraffe
var e3 = ((IEnumerable)ark).GetEnumerator(); // object
// since IEnumerable<Turtle> is the default implementation, we don't need
// a specific cast to be able to get its enumerator
var e4 = ark.GetEnumerator(); // turtle
Why isn't there a similar resolution for LINQ's Select extension method? Is there a proper design decision to allow the inconsistency between resolving the former, but not the latter?
// This is not allowed, but I don't see any reason why ..
// ark.Select(x => x); // turtle expected
// these are allowed
ark.Select<Turtle, Turtle>(x => x);
ark.Select<Giraffe, Giraffe>(x => x);

It's important to first understand what mechanism is being used to resolve the call to the extension method Select. C# uses a generic type inference algorithm which is fairly complex; see the C# specification for the details. (I really should write a blog article explaining it all; I recorded a video about it in 2006 but unfortunately it has disappeared.)
But basically, the idea of generic type inference on Select is: we have:
public static IEnumerable<R> Select<A, R>(
this IEnumerable<A> items,
Func<A, R> projection)
From the call
ark.Select(x => x)
we must deduce what A and R was intended.
Since R depends on A, and in fact is equal to A, the problem reduces to finding A. The only information we have is the type of ark. We know that ark:
Is Ark
Extends object
Implements IEnumerable<Giraffe>
Implements IEnumerable<Turtle>
IEnumerable<T> extends IEnumerable and is covariant.
Turtle and Giraffe extend Animal which extends object.
Now, if those are the only things you know, and you know that we're looking for IEnumerable<A>, what conclusions can you reach about A?
There are a number of possibilities:
Choose Animal, or object.
Choose Turtle or Giraffe by some tiebreaker.
Decide that the situation is ambiguous, and give an error.
We can reject the first option. A design principle of C# is: when faced with a choice between options, always choose one of the options or produce an error. C# never says "you gave me a choice between Apple and Cake so I choose Food". It always chooses from the choices you gave it, or it says that it has no basis on which to make a choice.
Moreover, if we chose Animal, that just makes the situation worse. See the exercise at the end of this post.
You propose the second option, and your proposed tiebreaker is "an implicitly implemented interface gets priority over an explicitly implemented interface".
This proposed tiebreaker has some problems, starting with there is no such thing as an implicitly implemented interface. Let's make your situation slightly more complicated:
interface I<T>
{
void M();
void N();
}
class C : I<Turtle>, I<Giraffe>
{
void I<Turtle>.M() {}
public M() {} // Used for I<Giraffe>.M
void I<Giraffe>.N() {}
public N() {}
public static DoIt<T>(I<T> i) {i.M(); i.N();}
}
When we call C.DoIt(new C()) what happens? Neither interface is "explicitly implemented". Neither interface is "implicitly implemented". Interface members are implicitly or explicitly implemented, not interfaces.
Now we could say "an interface that has all of its members implicitly implemented is an implicitly implemented interface". Does that help? Nope. Because in your example, IEnumerable<Turtle> has one member implicitly implemented and one member explicitly implemented: the overload of GetEnumerator that returns IEnumerator is a member of IEnumerable<Turtle> and you've explicitly implemented it.
(ASIDE: A commenter notes that the above is inelegantly worded; it is not entirely clear from the specification whether members "inherited" from "base" interfaces are "members" of the "derived" interface, or whether it is simply the case that a "derivation" relationship between interfaces is simply the statement of a requirement that any implementor of the "derived" interface must also implement the "base". The specification has historically been unclear on this point and it is possible to make arguments either way. Regardless, my point is that the derived interface requires you to implement a certain set of members, and some of those members can be implicitly implemented and some can be explicitly implemented, and we can count how many there are of each should we choose to.)
So now maybe the proposed tiebreaker is "count the members, and the interface that has the least members explicitly implemented is the winner".
So let's take a step back here and ask the question: how on earth would you document this feature? How would you explain it? Suppose a customer comes to you and says "why are turtles being chosen over giraffes here?" How would you explain it?
Now suppose the customer asks "how can I make a prediction about what the compiler will do when I write the code?" Remember, that customer might not have the source code to Ark; it might be a type in a third-party library. Your proposal makes the invisible-to-users implementation decisions of third parties into relevant factors that control whether other people's code is correct or not. Developers generally are opposed to features that make it impossible for them to understand what their code does, unless there is a corresponding boost in power.
(For example: virtual methods make it impossible to know what your code does, but they are very useful; no one has made the argument that this proposed feature has a similar usefulness bonus.)
Suppose that third party changes a library so that a different number of members are explicitly implemented in a type you depend on. Now what happens? A third party changing whether or not a member is explicitly implemented can cause compilation errors in other people's code.
Even worse, it can not cause a compilation error; imagine a situation in which someone makes a change just in the number of methods that are implicitly implemented, and those methods are not even methods that you call, but that change silently causes a sequence of turtles to become a sequence of giraffes.
Those scenarios are really, really bad. C# was carefully designed to prevent this kind of "brittle base class" failure.
Oh, but it gets worse. Suppose we did like this tiebreaker; could we even implement it reliably?
How can we even tell if a member is explicitly implemented? The metadata in the assembly has a table that lists what class members are explicitly mapped to what interface members, but is that a reliable reflection of what is in the C# source code?
No, it is not! There are situations in which the C# compiler must secretly generate explicitly implemented interfaces on your behalf in order to satisfy the verifier (describing them would be quite off topic). So you cannot actually tell very easily how many interface members the type's implementor decided to implement explicitly.
It gets worse still: suppose the class is not even implemented in C#? Some languages always fill in the explicit interface table, and in fact I think Visual Basic might be one of those languages. So your proposal is to make the type inference rules possibly different for classes authored in VB than an equivalent type authored in C#.
Try explaining that to someone who just ported a class from VB to C# to have an identical public interface, and now their tests stop compiling.
Or, consider it from the perspective of the person implementing class Ark. If that person wishes to express the intention "this type can be used as both a sequence of turtles and giraffes, but if there is an ambiguity, choose turtles". Do you believe that any developer who wished to express that belief would naturally and easily come to the conclusion that the way to do that is to make one of the interfaces more implicitly implemented than the other?
If that were the sort of thing that developers needed to be able to disambiguate, then there should be a well-designed, clear, discoverable feature with those semantics. Something like:
class Ark : default IEnumerable<Turtle>, IEnumerable<Giraffe> ...
for example. That is, the feature should be obvious and searchable, rather than emerging by accident from an unrelated decision about what the public surface area of the type should be.
In short: The number of interface members that are explicitly implemented is not a part of the .NET type system. It's a private implementation strategy decision, not a public surface that the compiler should use to make decisions.
Finally, I've left the most important reason for last. You said:
I am not looking on feedback whether designing a class this way is considered best practice.
But that is an extremely important factor! The rules of C# are not designed to make good decisions about crappy code; they're designed to make crappy code into broken code that does not compile, and that has happened. The system works!
Making a class that implements two different versions of the same generic interface is a terrible idea and you should not do it. Because you should not do it, there is no incentive for the C# compiler team to spend even a minute figuring out how to help you do it better. This code gives you an error message. That is good. It should! That error message is telling you you're doing it wrong, so stop doing it wrong and start doing it right. If it hurts when you do that, stop doing that!
(One can certainly point out that the error message does a poor job of diagnosing the problem; this leads to another whole bunch of subtle design decisions. It was my intention to improve that error message for these scenarios, but the scenarios were too rare to make them a high priority and I did not get to it before I left Microsoft in 2012. Apparently no one else has made it a priority in the years that followed either.)
UPDATE: You ask why a call to ark.GetEnumerator can do the right thing automatically. That is a much easier question. The principle here is a simple one:
Overload resolution chooses the best member that is both accessible and applicable.
"Accessible" means that the caller has access to the member because it is "public enough", and "applicable" means "all the arguments match their formal parameter types".
When you call ark.GetEnumerator() the question is not "which implementation of IEnumerable<T> should I choose"? That's not the question at all. The question is "which GetEnumerator() is both accessible and applicable?"
There is only one, because explicitly implemented interface members are not accessible members of Ark. There is only one accessible member, and it happens to be applicable. One of the sensible rules of C# overload resolution is if there is only one accessible applicable member, choose it!
Exercise: What happens when you cast ark to IEnumerable<Animal>? Make a prediction:
I will get a sequence of turtles
I will get a sequence of giraffes
I will get a sequence of giraffes and turtles
I will get a compile error
I will get something else -- what?
Now try out your prediction and see what really happens. Draw conclusions as to whether it is a good or bad idea to write types that have multiple constructions of the same generic interface.

Related

Adding Class<derived> to List<Class<Interface>> [duplicate]

What is the real reason for that limitation? Is it just work that had to be done? Is it conceptually hard? Is it impossible?
Sure, one couldn't use the type parameters in fields, because they are allways read-write. But that can't be the answer, can it?
The reason for this question is that I'm writing an article on variance support in C# 4, and I feel that I should explain why it is restricted to delegates and interfaces. Just to inverse the onus of proof.
Update:
Eric asked about an example.
What about this (don't know if that makes sense, yet :-))
public class Lookup<out T> where T : Animal {
public T Find(string name) {
Animal a = _cache.FindAnimalByName(name);
return a as T;
}
}
var findReptiles = new Lookup<Reptile>();
Lookup<Animal> findAnimals = findReptiles;
The reason for having that in one class could be the cache that is held in the class itself. And please don't name your different type pets the same!
BTW, this brings me to optional type parameters in C# 5.0 :-)
Update 2: I'm not claiming the CLR and C# should allow this. Just trying to understand what led to that it doesnt.
First off, as Tomas says, it is not supported in the CLR.
Second, how would that work? Suppose you have
class C<out T>
{ ... how are you planning on using T in here? ... }
T can only be used in output positions. As you note, the class cannot have any field of type T because the field could be written to. The class cannot have any methods that take a T, because those are logically writes. Suppose you had this feature -- how would you take advantage of it?
This would be useful for immutable classes if we could, say, make it legal to have a readonly field of type T; that way we'd massively cut down on the likelihood that it be improperly written to. But it's quite difficult to come up with other scenarios that permit variance in a typesafe manner.
If you have such a scenario, I'd love to see it. That would be points towards someday getting this implemented in the CLR.
UPDATE: See
Why isn't there generic variance for classes in C# 4.0?
for more on this question.
As far as I know, this feature isn't supported by CLR, so adding this would require significant work on the CLR side as well. I believe that co- and contra-variance for interfaces and delegates was actually supported on CLR before the version 4.0, so this was a relatively straightforward extension to implement.
(Supporting this feature for classes would be definitely useful, though!)
If they were permitted, useful 100% type-safe (no internal typecasts) classes or structures could be defined which were covariant with regard to their type T, if their constructor accepted one or more T's or T supplier's. Useful, 100%-type-safe classes or structures could be defined which were contravariant with respect to T if their constructors accepted one or more T consumers. I'm not sure there's much advantage of a class over an interface, beyond the ability to use "new" rather than using a static factory method (most likely from a class whose name is similar to that of the interface), but I can certainly see usage cases for having immutable structures support covariance.

Is there any advantage in disallowing interface implementation for existing classes?

In static OOP languages, interfaces are used in order to declare that several classes share some logical property - they are disposable, they can be compared to an int, they can be serialized, etc.
Let's say .net didn't have a standard IDisposable interface, and I've just came up with this beautiful idea:
interface IDiscardable { void Discard(); }
My app uses a lot of System.Windows.Forms, and I think that a Form satisfies the logical requirements for being an IDiscardable. The problem is, Form is defined outside of my project, so C# (and Java, C++...) won't allow me to implement IDiscardable for it. C# doesn't allow me to formally represent the fact that a Form can be discarded ( and I'll probably end up with a MyForm wrapper class or something.
In contrast, Haskell has typeclasses, which are logically similar to interfaces. A Show instance can be presented (or serialized) as a string, Eq allows comparisons, etc. But there's one crucial difference: you can write a typeclass instance (which is similar to implementing an interface) without accessing the source code of a type. So if Haskell supplies me with some Form type, writing an Discardable instance for it is trivial.
My question is: from a language designer perspective, is there any advantage to the first approach? Haskell is not an object oriented language - does the second approach violates OOP in any way?
Thanks!
This is a difficult question, which stems from a common misunderstanding. Haskell type classes (TC), are said to be "logically similar" to the interfaces or abstract classes (IAC) from object-oriented programming languages. They are not. They represent different concepts about types and programming languages: IAC are a case of subtyping, while TC is a form of parametric polymorphism.
Nevertheless, since your questions are methodological, here I answer from a methodological side. To start with the second question:
does the second approach [that of extending the implementation of a class outside the class] violate OOP in any way
Object oriented programming is a set of ideas to describe the execution of a program, the main elements of an execution, how to specify these elements in the program's code, and how to structure a program so as to separate the specification of different elements. In particular, OOP is based in these ideas:
At any state of its execution, a process (executing program) consists of a set of objects. This set is dynamic: it may contain different objects at different states, via object creation and destruction.
Every object has an internal state represented by a set of fields, which may include references to other related objects. Relations are dynamic: the same field of the same object a may at different states point to different objects.
Every object can receive some messages from another object. Upon receiving a message, the object may alter its state and may send messages to objects in its fields.
Every object is an instance of a class: the class describes what fields the object has, what messages it can receive, and what it does upon receiving a message.
In an object a, the same field a.f may at different states point to
different objects, which may belong to different classes. Thus, a needs not to know to what class those objects b belong; it only needs to know what messages do those objects accept. For this reason, the type of those fields can be an interface.
The interface declares a set of messages that an object can receive. The class specifies explicitly what interfaces are satisfied by the objects of that class.
My answer to the question: in my opinion yes.
Implementing an interface (as suggested in the example) outside a class breaks one of these ideas: that the class of the object describes the complete set of messages that objects in that class can receive.
You may like to know, though, that this is (in part) what "Aspects", as in AspectJ, are about. An Aspect describes the implementation of a certain "method" in several classes, and these implementations are incorportated (weaved) into the class.
To answer back the first question, "is there any advantage to the first approach", the answer would be also yes: that all the behaviour of an object (what messages it answers to) is only described in one place, in the class.
Well, the Haskell approach does have one disadvantage, which is when you write, for example, two different libraries that each provides its own implementation of interface Foo for the same external type (provided by yet a third library). In this case now these two libraries can't be used at the same time in the same program. So if you call lack of a disadvantage an advantage, then I guess that would be one advantage for the OOP language way of doing this—but it's a pretty weak advantage.
What I would add to this, however, is that Haskell type classes are a bit like OOP interfaces, but not entirely like them. But type classes are also a bit like the Strategy and Template Method patterns; a type class can be simulated by explicitly passing around a "dictionary" object that provides implementations for the type class operations. So the following Haskell type class:
class Monoid m where
mempty :: m
mappend :: m -> m -> m
...can be simulated with this explicit dictionary type:
data Monoid_ m = Monoid_ { _mempty :: m, _mappend :: m -> m -> m }
...or an OOP interface like this:
interface Monoid<M> {
M empty();
M append(M a, M b);
}
What type classes add on top of this is that the compiler will maintain and pass around your dictionaries implicitly. Sometimes in the Haskell community you get arguments about when and whether type classes are superior to explicit dictionary passing; see for example Gabriel Gonzalez's "Scrap your type classes" blog entry (and keep in mind that he doesn't 100% agree with what he says there!). So the OOP counterpart to this idea would be instead of extending the language to allow external implements declarations, what are the drawbacks to just explicitly using Strategies or Template Methods?
What you are describing is the adapter pattern. The act of composing an object in a new type that provides some additional behavior to the underlying type, in this case the implementation of another interface.
As with so many design patterns, different languages choose different design patterns to incorporate directly into the language itself and provide special language support, often in the form of a more concise syntax, while other patterns are need to be implemented through the use of other mechanisms without their own special syntax.
C# doesn't have special language support for the adapter pattern, you need to create a new explicit type that composes your other type, implements the interface, and uses the composed type to fulfill the interface's contract. Is it possible for them to add such a feature to the language, sure. Like any other feature request in existence it needs to be designed, implemented, tested, documented, and all sorts of other expenses accounted for. This feature has (thus far) not made the cut.
What you are describing is called duck typing, after the phrase "If it walks like a duck, swims like a duck, and quacks like a duck, then it's a duck".
C# actually does allow dynamic (run-time) duck typing through the dynamic keyword. What it doesn't allow is static (compile-time) duck typing.
You'd probably need somebody from Microsoft to come along and provide the exact reasons this doesn't exist in C#, but here are some likely candidates:
The "minus 100 points" philosophy to adding features. It's not just enough for a feature to have no drawbacks, to justify the effort put into implementing, testing, maintaining and supporting a language feature, it has to provide a clear benefit. Between the dynamic keyword and the adapter pattern, there's not many situations where this is useful. Reflection is also powerful enough that it would be possible to effectively provide duck typing, for example I believe it'd be relatively straightforward to use Castle's DynamicProxy for this.
There are situations where you want a class to be able to specify how it is accessed. For example, fluent APIs often control the valid orderings and combinations of chained methods on a class through the use of interfaces. See, for example, this article. If my fluent class was designed around a grammar which stated that once method A was called, no other methods except B could be called, I could control this with interfaces like:
public class FluentExample : ICanCallAB
{
public ICanCallB A()
{
return this;
}
public ICanCallAB B()
{
return this;
}
}
public interface ICanCallA
{
void A();
}
public interface ICanCallAB : ICanCallA
{
void B();
}
Of course, a consumer could get around this using casting or dynamic, but at least in this case the class can state its own intent.
Related to the above point, an interface implementation is a declaration of meaning. For example, Tree and Poodle might both have a Bark() member, but I would want to be able to use Tree as an IDog.

What is the origin of CS0060:The direct base class of a class type must be at least as accessible as the class type itself

I just ran into this basic rule about inheritance in .net:
CS0060:The direct base class of a class type must be at least as accessible as the class type itself
I'm curious why this rule was developed.
Does anyone know why this kind of inheritance is preferred?
Are there any languages that do it differently.
// CS0060.cs
class MyClass
// try the following line instead
// public class MyClass
{
}
public class MyClass2 : MyClass // CS0060
{
public static void Main()
{
}
}
Thanks
I'm curious why this rule was developed. Does anyone know why this kind of inheritance is preferred? Are there any languages that do it differently?
The second question is much easier to answer than the first. Yes, other languages do it differently. In particular, C++ allows "private inheritance"; that is, the inheritance relationship becomes a private implementation detail of the class. If C# had private inheritance then clearly the base class could be less accessible than the derived class. But C# does not have private inheritance.
The first question is difficult to answer because "why" questions are inherently a bad fit for Stack Overflow. The only correct answer to "why was this rule developed?" is "because the language design committee decided that this was the best compromise when given many competing design goals".
That's probably not a satisfying answer. To answer this question properly would involve not just listing all of those design goals and their relative merits, but also describing the mental state of each member of the design team at the time the decision was made, and also describing by what process the various conflicts that arose were resolved. This decision was made thirteen years ago, so that trail is very cold indeed.
I was not in that room on that day thirteen years ago but I can give you some idea of the factors that the design committee would have considered when deciding whether to allow private inheritance:
Impact on "concept count". (How many related concepts does the user have to understand in order to use the feature correctly? How many new concepts does the feature add to the language?)
Similarity or dissimilarity of the feature to C++, which could be either helpful or confusing.
Success of the feature in C++. Do people use it in C++? Do they use it correctly? Does every C++ user understand this feature well enough to make a good choice?
Amount of interaction with other language features. Such a feature would change name lookup and overload resolution in potentially subtle or confusing ways.
Level of consistency with related language features. (Interfaces are allowed to be less accessible.)
Difficulty of implementation.
And many more factors.
Since I don't have the three or four hours to spare that it would take me to write up a detailed analysis of all those factors for this feature, and then try to retroactively psychoanalyze the design team, I think you're going to have to live with your curiosity unfulfilled.
I recommend against asking questions like this on StackOverflow in the future. Try to stick to specific technical questions about actual code that have precise answers.
class BaseClass {...}
public class MyClass: BaseClass {...} // Error
http://msdn.microsoft.com/en-us/library/cx03xt0t.aspx
This is mentioned in the C# language specification and also this makes perfect sense because in your case the public class can be used in "public" context with public accessibility level allowing the access of a non-public class which is your base class and this would be the wrong behaviour.
According to C# Language Specification 5.0:
(Download the spec from http://www.microsoft.com/en-us/download/details.aspx?id=7029)
The following accessibility constraints exist:
• The direct base class of a class type must be at least as accessible as the class type itself.
• The explicit base interfaces of an interface type must be at least as accessible as the interface type itself.
• The return type and parameter types of a delegate type must be at least as accessible as the delegate type itself.
• The type of a constant must be at least as accessible as the constant itself.
• The type of a field must be at least as accessible as the field itself.
• The return type and parameter types of a method must be at least as accessible as the method itself.
• The type of a property must be at least as accessible as the property itself.
• The type of an event must be at least as accessible as the event itself.
• The type and parameter types of an indexer must be at least as accessible as the indexer itself.
• The return type and parameter types of an operator must be at least as accessible as the operator itself.
• The parameter types of an instance constructor must be at least as accessible as the instance constructor itself.
All subsequent classes must have at least the same accessibility as the MyClass2 in your example.
This is logical, hence the following example.
When you have a internal class A with a public property called Prop. How do you think the outside world would know your derived public class B has a property Prop if the base class isn't public also?
I see your point, #mohammed sameeh. What is the value of this? Or what would be the side effects if .net behaved differently, if it tried to allow this?
#Anirudh was getting to that, when he talked about the security of that base class.
If you didn't have this restriction, the security model of consistently hiding "private"/"internal" things could be broken - or else very confusing!
That's really the biggest potential side effect, wrongly exposing properties and methods.
Since the child class, by definition, inherits the parent's properties & methods, how should they be considered in this case?
Rather than having (even more) rules about how properties & methods are exposed in inheritance and subclassing, .net simplifies things by maintaining a hierarchy of exposure and enforcing it.
Someone else might have a cool point to make about what would happen to type casts or the like without the restriction.
Certainly other rules could exist. It might be interesting to see another language that does it differently.
But for sure we want some kind of rules, so when someone else consumes your class or assembly, you know what to expect.
class MyClass
{
}
public class MyClass2 : MyClass // CS0060
{
public static void Main()
{
}
}
the causes of this error is beacuse the MyClass is not public so you need it put public just add public before class MyClass

Reflexive type parameter constraints: X<T> where T : X<T> ‒ any simpler alternatives?

Every so often I am making a simple interface more complicated by adding a self-referencing ("reflexive") type parameter constraint to it. For example, I might turn this:
interface ICloneable
{
ICloneable Clone();
}
class Sheep : ICloneable
{
ICloneable Clone() { … }
} //^^^^^^^^^^
Sheep dolly = new Sheep().Clone() as Sheep;
//^^^^^^^^
into:
interface ICloneable<TImpl> where TImpl : ICloneable<TImpl>
{
TImpl Clone();
}
class Sheep : ICloneable<Sheep>
{
Sheep Clone() { … }
} //^^^^^
Sheep dolly = new Sheep().Clone();
Main advantage: An implementing type (such as Sheep) can now refer to itself instead of its base type, reducing the need for type-casting (as demonstrated by the last line of code).
While this is very nice, I've also noticed that these type parameter constraints are not intuitive and have the tendency to become really difficult to comprehend in more complex scenarios.*)
Question: Does anyone know of another C# code pattern that achieves the same effect or something similar, but in an easier-to-grasp fashion?
*) This code pattern can be unintuitive and hard to understand e.g. in these ways:
The declaration X<T> where T : X<T> appears to be recursive, and one might wonder why the compiler doesn't get stuck in an infinite loop, reasoning, "If T is an X<T>, then X<T> is really an X<X<…<T>…>>." (But constraints obviously don't get resolved like that.)
For implementers, it might not be obvious what type should be specified in place of TImpl. (The constraint will eventually take care of that.)
Once you add more type parameters and subtyping relationships between various generic interfaces to the mix, things get unmanageable fairly quickly.
Main advantage: An implementing type can now refer to itself instead of its base type, reducing the need for type-casting
Though it might seem like by the type constraint referring to itself it forces the implementing type to do the same, that's actually not what it does. People use this pattern to try to express patterns of the form "an override of this method must return the type of the overriding class", but that's not actually the constraint expressed or enforced by the type system. I give an example here:
https://ericlippert.com/2011/02/02/curiouser-and-curiouser/
While this is very nice, I've also noticed that these type parameter constraints are not intuitive and have the tendency to become really difficult to comprehend in more complex scenarios
Yep. I try to avoid this pattern. It's hard to reason about.
Does anyone know of another C# code pattern that achieves the same effect or something similar, but in an easier-to-grasp fashion?
Not in C#, no. You might consider looking at the Haskell type system if this sort of thing interests you; Haskell's "higher types" can represent those sorts of type patterns.
The declaration X<T> where T : X<T> appears to be recursive, and one might wonder why the compiler doesn't get stuck in an infinite loop, reasoning, "If T is an X<T>, then X<T> is really an X<X<…<T>…>>."
The compiler does not ever get into infinite loops when reasoning about such simple relationships. However, nominal subtyping of generic types with contravariance is in general undeciable. There are ways to force the compiler into infinite regresses, and the C# compiler does not detect these and prevent them before embarking on the infinite journey. (Yet. I am hoping to add detection for this in the Roslyn compiler but we'll see.)
See my article on the subject if this interests you. You'll want to read the linked-to paper as well.
https://ericlippert.com/2008/05/07/covariance-and-contravariance-part-11-to-infinity-but-not-beyond/
Unfortunately, there isn't a way to fully prevent this, and a generic ICloneable<T> with no type constraints is enough. Your constraint only limits possible parameters to classes which themselves implement it, which doesn't mean they are the ones currently being implemented.
In other words, if a Cow implements ICloneable<Cow>, you will still easily make Sheep implement ICloneable<Cow>.
I would simply use ICloneable<T> without constraints for two reasons:
I seriously doubt you will ever make a mistake of using a wrong type parameter.
Interfaces are meant to be contracts for other parts of code, not to be used to code on autopilot. If a part of a code expects ICloneable<Cow> and you pass a Sheep which can do that, it seems perfectly valid from that point.

Why generic interfaces are not co/contravariant by default?

For example IEnumerable<T> interface:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
In this interface the generic type is used only as a return type of interface method and not used as a type of method arguments thus it can be covariant. Giving this, can't compiler theoretically infer the variance from the interface? If it can, why does C# requires us to set co/contravariance keywords explicitly.
Update: As Jon Skeet mentioned this question can be spited into sub-questions:
Can compiler infer generic type's co/contravariance by how it is used inside current generic type and all it's base types?
For example.. How many generic interface parameters from .NET Framework 4.0 can be marked co/contravariant automatically without any ambiguity? About 70%, 80%, 90% or 100%?
If it can, should it apply co/contravariance to generic types by default? At least to those types which it is capable to analyze and infer co/contravariance from the type usage.
Well, there are two questions here. Firstly, could the compiler always do so? Secondly, should it (if it can)?
For the first question, I'll defer to Eric Lippert, who made this comment when I brought exactly this issue up in the 2nd edition of C# in Depth:
It's not clear to me that we reasonably could even if we wanted to. We can easily come up
with situations that require expensive global analysis of all the interfaces in a program
to work out the variances, and we can easily come up with situations where either it's
<in T, out U> or <out T, in U> and no way to decide between them. With both bad
performance and ambiguous cases it's an unlikely feature.
(I hope Eric doesn't mind me quoting this verbatim; he's previously been very good about sharing such insights, so I'm going by past form :)
On the other hand, I suspect there are still cases where it can be inferred with no ambiguity, so the second point is still relevant...
I don't think it should be automatic even where the compiler can unambiguously know that it's valid in just one way. While expanding an interface is always a breaking change to some extent, it's generally not if you're the only one implementing it. However, if people are relying on your interface to be variant, you may not be able to add methods to it without breaking clients... even if they're just callers, not implementers. The methods you add may change a previously-covariant interface to become invariant, at which point you break any callers who are trying to use it covariantly.
Basically, I think it's fine to require this to be explicit - it's a design decision you should be making consciously, rather than just accidentally ending up with covariance/contravariance without having thought about it.
This article explains that there are situations that the compiler cannot infer and so it provides you with the explicit syntax:
interface IReadWriteBase<T>
{
IReadWrite<T> ReadWrite();
}
interface IReadWrite<T> : IReadWriteBase<T>
{
}
What do you infer here in or out, both work?

Categories

Resources