I've done a bit of google on this and have not found anything to explain the syntax..
So I'm using Action<T> for a producer consumer where Action<T> is the consumer action to perform. I right clicked on Action<T> - 'go to definition' to see its definition and this is what I was shown
public delegate void Action<in T>(T obj);
Hmmm... I've been using generics for quite a while now and have not ever used nor seen the syntax of <in T>
Anyone got a nice summation to hand to explain the syntax and what it produces?
Thanks. D
The in and out variance modifiers for generic types has been introduced in C# 4.0 to allow co and contra variance to generic types.
For generic type parameters, the in keyword specifies that the type parameter is contravariant.
For generic type parameters, the out keyword specifies that the type parameter is covariant.
And from Variance in Generic Interfaces (C# and Visual Basic) on MSDN:
Covariance permits a method to have a more derived return type than that defined by the generic type parameter of the interface.
Contravariance permits a method to have argument types that are less derived than that specified by the generic parameter of the interface.
Related
I Have the following piece of code. I have not specified any generic parameters and IN/OUT(variance) for this delegate. If I understand the meaning of invariance correctly i should not be able to return object of Base type since my delegate mentions return type of object.
Is my understanding of invariance wrong?
class Program
{
public delegate object SampleDelegate(Base b);
static void Main(string[] args)
{
List<Base> listBases = new List<Base>(){new Base{}, new Base{}};
SampleDelegate newDel = new SampleDelegate(ProcessBase);
newDel(new Base() { });
Console.ReadLine();
}
public static Base ProcessBase(Base b)
{
return b;
}
public class Base
{
}
public class Derived : Base
{
}
}
If I understand the meaning of invariance correctly i should not be able to return object of Base type since my delegate mentions return type of object. Is my understanding of invariance wrong?
Since you can compile and run that program, you already know the answer to that question. Yes.
Let's ask the question you meant to ask:
Since the delegate is not even generic, clearly generic variance on delegates does not apply. Why then can I make a covariant conversion from a method returning Base to a delegate type that requires that the method return object?
Clearly generic covariance is not the kind of covariance that is relevant; there is an entirely different rule at play here. This conversion was first allowed in C# 2.0. When converting from a method group to a delegate, the method chosen from the method group may have a return type more general than the delegate's return type, provided that both types are reference types. And similarly for the parameter types, which are contravariant.
The feature of allowing conversions between generic delegate types constructed with reference types to similarly be covariant and contravariant was added -- by me, incidentally -- to C# 4.0.
All delegates allow a degree of covariance in that one can assign a method with a more derived return type to a delegate. This is what you did here, where you had a method with return type Base and a delegate of return type object.
Essentially the value returned is cast to object on invocation, which will always work, because the cast from Base to object is always going to work.
Or to look at it another way, to call ProcessBase via a delegate of type SampleDelegate is to call (object)ProcessBase(theArgument).
You can think of this as the opposite to how we can always call a method with arguments of more derived types. E.g. we can do ReferenceEquals("abc", 1) because "abc" can be cast to object as a more derived type, and 1 can be cast to òbject` by boxing.
And indeed, for similar reasons you could assign ProcessBase to a delegate defined as public delegate object SampleDelegate(Derived b); because it would always be safe to call it, because it could only ever be called with a Derived argument, which could always be cast to Base on calling.
More often when we talk about covariance and contravariance with delegates in C#, we mean that of covariant and contravariant type parameters.
(Mainly because the type of variance described above was in the language since 2.0, and the type I'll describe below since 4.0, so the latter type was "news" to already-working C# programmers).
If we have a generic delegate defined as:
public delegate TResult MyDelegate<TArg, TResult>(TArg argument);
Then consider the following:
MyDelegate<Base, Derived> del = b => null;//simple example.
MyDelegate<Derived, Derived> del2 = del; // compiler error 1. CS0029: Cannot implicitly convert type
MyDelegate<Base, Base> del3 = del; // compiler error 2. CS0029: Cannot implicitly convert type
MyDelegate<Derived, Base> del4 = del; // compiler error 3. CS0029: Cannot implicitly convert type
We aren't allowed to do either of the two conversions, but when you think about it, what could possibly go wrong here?
If we change the definition of MyDelegate to:
public delegate TResult MyDelegate<in TArg, TResult>(TArg argument);
Then the first error goes away, because the in allows contravariance on TArg.
If we change the definition to:
public delegate TResult MyDelegate<TArg, out TResult>(TArg argument);
Then the second error goes away, because the out allows covariance on TResult.
Finally if we change the definition to:
public delegate TResult MyDelegate<in TArg, out TResult>(TArg argument);
Then all three errors go away, because we have both the in and the out.
The rules of covariance an contravariance won't allow you to assign anything illogical. E.g.:
public delegate TResult MyDelegate<out TArg, in TResult>(TArg argument);
Has two errors: We cannot expect to be safely covariant on TArg nor safely contravariant on TResult; if we were allowed to do this, we would be allowed to assign delegates that didn't work to other delegate types.
The Func and Action types provide examples of this. For example, one of them is defined as:
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
And hence we can assign a Func<object, object, string> to a variable of type Func<string, string, object> because all calls involved will work, but we cannot assign a Func<string, string, object> to a variable of type Func<object, object, string>, as this doesn't hold.
Generic covariance and contravariance also holds with interfaces, allowing us to e.g. assign an IEnumerable<string> to a variable of type IEnumerable<object> because everything we can call on an IEnumerable<object> we can safely call on an IEnumerable<string>.
Is covariance all about accepting values?
I am learning the C# through the CLR via C# book. And I come across the following excerpt:
Since T is covariant, it is possible to have the following code compile and run successfully:
// This method accepts an IEnumerable of any reference type
Int32 Count(IEnumerable<Object> collection) { ... }
...
// The call below passes an IEnumerable<String> to Count
Int32 c = Count(new[] { "Grant" });
I am confused here. Because the covariance is about having the type which is one of the base types of the required type. And as such the covariance is used only in the context of the return types. While in the example above we have a String (which is derived from Object, so that is contravariant, but not covariant) which is used in the context of passing arguments (but not returning values).
So, should we use in the example above the contravariant instead of the covariant (meaning that there is an error in the book)?
UPDATE
After the comments I got another question. Are the following definitions correct?
Contravariant Meaning that the generic type parameter can change from a class to a class
derived from it. In C#, you indicate contravariant generic type parameters with the in keyword.
Contravariant generic type parameters can appear only in input positions such as a method’s
argument.
Covariant Meaning that the generic type argument can change from a class to one of its base
classes. In C#, you indicate covariant generic type parameters with the out keyword. Covariant
As Josh pointed out the book is correct.
You can check this link if you want to confirm it from another source.
IEnumerable<Cat> is a subtype of IEnumerable<Animal>. The subtyping is preserved because IEnumerable<T> is covariant on T.
The two keywords in C# for those concepts are out for covariant and in for contravariant. In the IEnumerable<T> case this translate to IEnumerable<out T>.
Hope this helps.
UPDATE
You would have to inverse your definitions as follows.
Covariant Meaning that the generic type parameter can be a certain class and all the derived classes from it (IEnumerable<Object> can be a IEnumerable<String> since String is a subtype of Object). In C#, you indicate covariant generic type parameters with the out keyword.
Contravariant Meaning that the generic type argument can change from a
class to one of its base classes. In C#, you indicate contravariant
generic type parameters with the in keyword.
Given this code:
class C
{
C()
{
Test<string>(A); // fine
Test((string a) => {}); // fine
Test((Action<string>)A); // fine
Test(A); // type arguments cannot be inferred from usage!
}
static void Test<T>(Action<T> a) { }
void A(string _) { }
}
The compiler complains that Test(A) can't figure out T to be string.
This seems like a pretty easy case to me, and I swear I've relied far more complicated inference in other generic utility and extension functions I've written. What am I missing here?
Update 1: This is in the C# 4.0 compiler. I discovered the issue in VS2010 and the above sample is from a simplest-case repro I made in LINQPad 4.
Update 2: Added some more examples to the list of what works.
Test(A);
This fails because the only applicable method (Test<T>(Action<T>)) requires type inference, and the type inference algorithm requires that each each argument be of some type or be an anonymous function. (This fact is inferred from the specification of the type inference algorithm (§7.5.2)) The method group A is not of any type (even though it is convertable to an appropriate delegate type), and it is not an anonymous function.
Test<string>(A);
This succeeds, the difference being that type inference is not necessary to bind Test, and method group A is convertable to the required delegate parameter type void Action<string>(string).
Test((string a) => {});
This succeeds, the difference being that the type inference algorithm makes provision for anonymous functions in the first phase (§7.5.2.1). The parameter and return types of the anonymous function are known, so an explicit parameter type inference can be made, and a correspondense is thereby made between the types in the anonymous function (void ?(string)) and the type parameter in the delegate type of the Test method’s parameter (void Action<T>(T)). No algorithm is specified for method groups that would correspond to this algorithm for anonymous functions.
Test((Action<string>)A);
This succeeds, the difference being that the untyped method group parameter A is cast to a type, thereby allowing the type inference of Test to proceed normally with an expression of a particular type as the only argument to the method.
I can think of no reason in theory why overload resolution could not be attempted on the method group A. Then—if a single best binding is found—the method group could be given the same treatment as an anonymous function. This is especially true in cases like this where the method group contains exactly one candidate and it has no type parameters. But the reason it does not work in C#4 appears to be the fact that this feature was not designed and implemented. Given the complexity of this feature, the narowness of its application, and the existance of three easy work-arounds, I am not going to be holding my breath for it!
I think it's because it's a two-step inference:
It has to infer that you want to convert A to a generic delegate
It has to infer what the type of the delegate parameter should be
I'm not sure if this is the reason, but my hunch is that a two-step inference isn't necessarily easy for the compiler.
Edit:
Just a hunch, but something is telling me the first step is the problem. The compiler has to figure out to convert to a delegate with a different number of generic parameters, and so it can't infer the types of the parameters.
This looks like a vicious circle to me.
Test method expects a parameter of delegate type constructed from generic type Action<T>. You pass in a method group instead: Test(A). This means compiler has to convert your parameter to a delegate type (method group conversion).
But which delegate type? To know the delegate type we need to know T. We didn't specify it explicitly, so compiler has to infer it to figure out the delegate type.
To infer the type parameters of the method we need to know the types of the method arguments, in this case the delegate type. Compiler doesn't know the argument type and thus fails.
In all other cases either type of argument is apparent:
// delegate is created out of anonymous method,
// no method group conversion needed - compiler knows it's Action<string>
Test((string a) => {});
// type of argument is set explicitly
Test((Action<string>)A);
or type parameter is specified explicitly:
Test<string>(A); // compiler knows what type of delegate to convert A to
P.S. more on type inference
You're passing the name of the Method A. The .Net framework CAN convert it to an Action, but it's implicit and it will not take responsibility for it.
But still, a method name is NOT an explicit Action<> Object. And therefor it won't infer the type as an Action type.
I could be wrong, but I imagine the real reason C# cannot infer the type is due to method overloading and the ambiguity that arises. For example, suppose I have the following methods: void foo (int) and void foo (float). Now if I write var f = foo. Which foo should the compiler pick? Likewise, the same problem happens with your example using Test(foo).
I would like to create the following class snippet
class Lookup<TKey,TValue,TCollection>
where TCollection : ICollection<>
{
public TCollection<TKey> _KeyCollection;
public TCollection<TValue> _ValueCollection;
}
Is this pattern in general possible in C#? In the current form the compiler does not like it. You can't seem to constrain a type parameter to be a generic. However it looks like it a reasonable thing to want to do. Is there any trick to achieve it?
Note: This question is specifically about generics and type constraints. It is not looking for a work around for what you think I might be trying to do in my wider application.
You can't constrain a generic type parameter to be an open generic type, which seems to be how you're attempting to use it in the rest of the class.
You asked for a spec reference, and there's not one place that seems to spell it out in a nice, concise manner.
The best I can find is in section 4.5 (from C# 5.0 spec):
As a type, type parameters are purely a compile-time construct. At run-time, each type parameter is bound to a run-time type that was specified by supplying a type argument to the generic type declaration. Thus, the type of a variable declared with a type parameter will, at run-time, be a closed constructed type (§4.4.2). The run-time execution of all statements and expressions involving type parameters uses the actual type that was supplied as the type argument for that parameter.
But in your attempt, TCollection won't match up with this text because it's asking for an non-closed type.
You can't have an open generic type as a constraint. You can, however, have a closed generic type:
class Lookup<TKey, TValue, TKeyCollection, TValueCollection>
where TKeyCollection : ICollection<TKey>
where TValueCollection : ICollection<TValue>
{
public TKeyCollection _KeyCollection;
public TValueCollection _ValueCollection;
}
It may not be pretty and there are a lot of type parameters, but it is possible.
I was reading the Covariance and Contravariance in C#.
According to my understanding,
If we have a class Animal and a derived class Cat then,
Covariance feature makes the compiler accepts passing a Cat type object to Animal type object and Contravariant is vice-versa.
Everything is ok till I read this line.
"To annotate type-covariance you use out parameter and for contravariant you use in parameter"
According to me, a parameter decorated with out keyword => the value must be assigned to that particular parameter in a function.
I have difficulties to associate the out keyword to covariance and in keyword to contravariant.
How are these two related ? Any super simple examples for both?
Thanks in advance.
Both covariance and contravariance in C# 4.0 refer to the ability of using a derived class instead of base class. The in/out keywords are compiler hints to indicate whether or not the type parameters will be used for input and output.
Covariance
Covariance in C# 4.0 is aided by out keyword and it means that a generic type using a derived class of the out type parameter is OK. Hence
IEnumerable<Fruit> fruit = new List<Apple>();
Since Apple is a Fruit, List can be safely used as IEnumerable
Contravariance
Contravariance is the in keyword and it denotes input types, usually in delegates. The principle is the same, it means that the delegate can accept more derived class.
public delegate void Func<in T>(T param);
This means that if we have a Func, it can be converted to Func.
Func<Fruit> fruitFunc = (fruit)=>{};
Func<Apple> appleFunc = fruitFunc;
Why are they called co/contravariance if they are basically the same thing?
Because even though the principle is the same, safe casting from derived to base, when used on the input types, we can safely cast a less derived type (Func) to a more derived type (Func), which makes sense, since any function that takes Fruit, can also take Apple.
out is a contextual keyword, i.e. depending on its placement, it means different things.
You are talking about the parameter modifier. But that's not what it is with regards to Co- and Contravariance. When the keyword is used in a generic interface definition, it is the generic modifier, which is something else completely.
out keyword serves different purposes. As you noted in the context of "generic type parameters" it acts as a keyword to make "covariance" work, another use is similar to ref keyword which we use to get multiple return values from a Method.
If you look at the documentation for out-keyword in MSDN two purposes of out keyword will be listed. Not to be confused it acts different based on the context.
You can find similarities with new keyoword also, it also serves different purposes. AFAIK they are
To create new instance of a class. object obj = new object();
To explicitly shadow base class method or property. protected new void BaseMethod(){}
Generic parameter constraint. private void MyGenericMethod<T>(T t) where T:new()
I think Microsoft guys make this feature very complexe by using not clear names for the feature name and not good keywords for the feature parameters.
I know this name from Covariance and contravariance of vectors (Mathe) and when I hear about it first time in C# I got a shock!
#JoesphAlbahari in his book C# 4 In a Nutshell have explained this topic very well page 109-112. I recommend you really to read it.