I need more information about variance in generics and delegates. The following code snippet does not compile:
Error CS1961 Invalid variance: The type parameter 'TIn' must be
covariantly valid on 'Test.F(Func)'. 'TIn' is
contravariant.
public interface Test<in TIn, out TOut>
{
TOut F (Func<TIn, TOut> transform);
}
The .net Func definition is as follows:
public delegate TResult Func<in T, out TResult> (T arg);
Why the compiler complains about TIn being contravariant and TOut - covariant while the Func expects exactly the same variance?
EDIT
The main constraint for me is that I want my Test interface to have TOut as covariant in order to use it something like this:
public Test<SomeClass, ISomeInterface> GetSomething ()
{
return new TestClass<SomeClass, AnotherClass> ();
}
Given that public class AnotherClass : ISomeInterface.
I need more information about variance in generics and delegates.
I wrote an extensive series of blog articles on this feature. Though some of it is out of date -- since it was written before the design was finalized -- there's lots of good information there. In particular if you need a formal definition of what variance validity is, you should carefully read this:
https://blogs.msdn.microsoft.com/ericlippert/2009/12/03/exact-rules-for-variance-validity/
See my other articles on my MSDN and WordPress blogs for related topics.
Why the compiler complains about TIn being contravariant and TOut - covariant while the Func expects exactly the same variance?
Let's slightly rewrite your code and see:
public delegate R F<in T, out R> (T arg);
public interface I<in A, out B>{
B M(F<A, B> f);
}
The compiler must prove that this is safe, but it is not.
We can illustrate that it is not safe by supposing that it is, and then discovering how it can be abused.
Let's suppose we have an Animal hierarchy with the obvious relationships, eg, Mammal is an Animal, Giraffe is a Mammal, and so on. And let's suppose that your variance annotations are legal. We should be able to say:
class C : I<Mammal, Mammal>
{
public Mammal M(F<Mammal, Mammal> f) {
return f(new Giraffe());
}
}
I hope you agree this is a perfectly valid implementation. Now we can do this:
I<Tiger, Animal> i = new C();
C implements I<Mammal, Mammal>, and we've said that the first one can get more specific, and the second can get more general, so we've done that.
Now we can do this:
Func<Tiger, Animal> f = (Tiger t) => new Lizard();
That's a perfectly legal lambda for this delegate, and it matches the signature of:
i.M(f);
And what happens? C.M is expecting a function that takes a giraffe and returns a mammal, but it's been given a function that takes a tiger and returns a lizard, so someone is going to have a very bad day.
Plainly this must not be allowed to happen, but every step along the way was legal. We must conclude that the variance itself was not provably safe, and indeed, it was not. The compiler is right to reject this.
Getting variance right takes more than simply matching the in and out annotations. You've got to do so in a manner that does not allow this sort of defect to exist.
That explains why this is illegal. To explain how it is illegal, the compiler must check that the following is true of B M(F<A, B> f);:
B is valid covariantly. Since it is declared "out", it is.
F<A, B> is valid contravariantly. It is not. The relevant portion of the definition of "valid contravariantly" for a generic delegate is: If the ith type parameter was declared as contravariant, then Ti must be valid covariantly. OK. The first type parameter, T, was declared as contravariant. Therefore the first type argument A must be valid covariantly. But it is not valid covariantly, because it was declared contravariant. And that's the error you're getting. Similarly, B is also bad because it must be valid contravariantly, but B is covariant. The compiler does not go on to find additional errors after it finds the first problem here; I considered it but rejected it as being a too-complex error message.
I note also that you would still have this problem even if the delegate were not variant; nowhere in my counterexample did we use the fact that F is variant in its type parameters. A similar error would be reported if we tried
public delegate R F<T, R> (T arg);
instead.
Variance is about being able to replace type parameters with either more or less derived types than originally declared. For example, IEnumerable<T> is covariant for T, meaning if you start with a reference to a IEnumerable<U> object, you can assign that reference to a variable having type IEnumerable<V>, where V is assignable from U (e.g. U inherits V). This works, because any code trying to use the IEnumerable<V> wants to receive only values of V, and since V is assignable from U, receiving only values of U is also valid.
For covariant parameters like T, you have to assign to a type where the destination type is the same as T, or assignable from T. For contravariant parameters, it has to go the other way. The destination type has to be the same as, or assignable to, the type parameter.
So, how does the code you are trying to write work in that respect?
When you declare Test<in TIn, out TOut>, you are promising that it will be valid to assign an instance of that interface Test<TIn, TOut> to any destination having the type Test<U, V> where U can be assigned to TIn and TOut can be assigned to V (or they are identical, of course).
At the same time, let's consider what your transform delegate is to expect. The Func<T, TResult> type variance requires that if you want to assign that value to something else, it also meets the variance rules. That is, a destination Func<U, V> must have U assignable from T, and TResult assignable from V. This ensures that your delegate target method which is expecting to receive a value of U will get one of those, and the value returned by the method, having type V, can be accepted by the code receiving it.
Importantly, your interface method F() is the one doing the receiving! The interface declaration promises that TOut will be used only as output from the interface members. But through the use of the transform delegate, the method F() will receive a value of TOut, making that input to the method. Likewise, the method F() is allowed to pass a value of TIn to the transform delegate, making that an output of your interface implementation, even though you've promised that TIn is used only as input.
In other words, every layer of call reverses the sense of the variance. Members in the interface have to use covariant type parameters as output only and contravariant parameters as input only. But those parameters become reversed in sense when they are used in delegate types passed to or returned from interface members, and have to comply with the variance in that respect.
A concrete example:
Suppose we have an implementation of your interface, Test<object, string>. If the compiler were to allow your declaration, you'd be permitted to assign a value of that implementation Test<object, string> to a variable having the type Test<string, object>. That is, the original implementation promises to allow as input any thing having type object and return only values having the type string. It's safe for code declared as Test<string, object> to work with this, because it will pass string objects to an implementation that requires objects values (string is an object), and it will receive values having the type object from an implementation that returns string values (again, string is an object, so also safe).
But your interface implementation expects code to pass a delegate of type Func<object, string>. If you were allowed to treat (as above) your interface implementation as a Test<string, object> instead, then the code using your re-cast implementation would be able to pass a delegate of Func<string, object> to the method F(). The method F() in the implementation is allowed to pass any value of type object to the delegate, but that delegate, being of type Func<string, object>, is expecting only values having the type string to be passed to it. If F() passes something else, e.g. just a plain old new object(), the delegate instance won't be able to use it. It's expecting a string!
So, in fact, the compiler is doing exactly what it's supposed to: it's preventing you from writing code that is not type-safe. As declared, if you were permitted to use that interface in a variant way, you would in fact be able to write code that while allowed at compile-time, could break at run-time. Which is the exact opposite of the whole point of generics: to be able to determine at compile-time that the code is type-safe!
Now, how to solve the dilemma. Unfortunately, there's not enough context in your question to know what the right approach is. It's possible that you simply need to give up on variance. Often, there's not actually any need to make types variant; it's a convenience in some cases, but not required. If that's the case, then just don't make the interface's parameters variant.
Alternatively, it's possible you really do want the variance and thought it would be safe to use the interface in a variant way. That's harder to solve, because your fundamental assumption was just incorrect and you will need to implement the code some other way. The code would compile if you could reverse the parameters in the Func<T, TResult>. I.e. make the method F(Func<TOut, TIn> transform). But there's not anything in your question that suggests that's actually possible in your scenario.
Again, without more context it's impossible to say what "other way" would work for you. But, hopefully now that you understand the hazard in the code the way you've written it now, you can revisit the design decision that led you to this not-type-safe interface declaration, and can come up with something that works. If you have trouble with that, post a new question that provides more detail as to why you thought this would be safe, how you're going to use the interface, what alternatives you've considered, and why none of those work for you.
TIn = the class knows how to read it, and the implementation is allowed to treat it as a type that is less derived than it actually is. You might pass it an instance that is more derived than expected, but that doesn't matter, because the derived class can do everything that the base class can do.
TOut = the implementation knows to to produce one, and the implementation is allowed to produce a type that is more derived than the caller is expecting. Again, it doesn't matter-- the caller can assign a more derived class to a less derived variable with no problem.
But--
If you pass the class a Func<TIn, TOut>, and you expect the class to be able to call it, then the class will have to be able to produce a TIn and read the TOut. Which is the opposite of the above.
Why can't it? Well, I already mentioned that the class can treat TIn as something that is less derived. If it attempts to call the function with an argument that is less derived, it won't work (what if the function is expecting to be able to call string.Length but the class passes it an object?). Also, if it attempts to read the results of the function as something that is more derived, that will fail as well.
You can eliminate the problem by eliminating the variance-- get rid of the in and out keywords-- which will render the class unable to substitute less/more derived types (this is called "invariance") but will allow you to both read and write the types.
Remove in and out -keywords from the interface definition:
public interface Test<TIn, TOut>{
TOut F (Func<TIn, TOut> transform);
}
remove the in and out key words:
public interface Test<TIn, TOut>
{
TOut F (Func<TIn, TOut> transform);
}
you can read about the meaning of them here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-generic-modifier
A type can be declared contravariant in a generic interface or delegate if it is used only as a type of method arguments and not used as a method return type
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-generic-modifier
The type parameter is used only as a return type of interface methods and not used as a type of method arguments.
I would like to define a non-generic delegate extending a generic delegate to define a default for the generic delegate type parameter, i.e. something like this (not a valid piece of C# code but an obvious-to-understand illustration for the concept I mean hopefully):
public delegate void MyDelegate<T>(T arg);
public delegate void MyDelegate(object arg) : MyDelegate<object>;
What is, if any, the correct way to declare this?
Needless to say I can just declare 2 independent delegates to achieve virtually same effect a way like this:
public delegate void MyDelegate<T>(T arg);
public delegate void MyDelegate(object arg);
but I'd like to do to make the actual relation between them (the fact a bare MyDelegate type is meant to equal MyDelegate<object>, the way like a class extending another class or literally) definite and make the following code will become valid if possible:
MyDelegate<object> d1;
MyDelegate d2;
MyDelegate d1 = d2;
Sorry, I may have been too harsh in saying you should know delegate types are sealed. It is clear in the specification, but I took a look at the latest version of the MSDN language documentation, and it does not seem to mention this at all. Well, anyway…they are sealed. 😊 You can't create a new class that inherits a delegate type, and you certainly can't use the delegate keyword to declare a new delegate type that inherits another delegate type (the keyword has a very specific syntax, and doesn't even allow an inheritance syntax).
It's still not really clear to me what you're trying to do. But, in some sense, a delegate type is an interface with just one member. It's more flexible, of course, because the implementation isn't in a single type, but can be any method from any type. But conceptually, the two are very similar.
In that sense, you could express your intent in code using an interface instead of a delegate. For example:
interface IDelegate<T>
{
void M(T arg);
}
interface IDelegateObject : IDelegate<object> { }
Of course, the problem with this is that now you need some type that will implement the interface in question. Any given type will only be able to implement any given interface once, so you lose a lot of the flexibility that delegate types would ordinarily give you.
But, you can do something like this:
IDelegate<object> d1;
IDelegateObject d2;
d1 = d2;
That is, since IDelegateObject inherits IDelegate<object>, and thus "is a" IDelegate<object>, you can then assign a value of type IDelegateObject, i.e. d2, to a variable of type IDelegate<object>, i.e. d1.
I'm reading this msdn article, the contravariance example (keyboard and mouse event) is great and useful, while the covariance example (Mammal and Dog) doesn't look so.
The keyboard and mouse event is great since you can use 1 handler for multiple cases; but I can't think of the advantages of assigning a handler that returns a more derived type to a handler returning base type, not to mention it looks like less common to have a delegate which cares about return type?
Could someone please provide a more practical example of covariance in delegate?
Here's a "real world" example where I implement a service locator. I want to make a class where I can register "factory" delegates that know how to produce instances of some type, then resolve instances of some type later on. Here is what that looks like:
interface ISomeService { ... }
class SomeService : ISomeService { ... }
class IocContainer
{
private readonly Dictionary<Type, Func<object>> _factories = new Dictionary<Type, Func<object>>();
public void Register<T>(Func<T> factory)
where T: class
{
_factories[typeof(T)] = factory;
}
// Note: this is C#6, refactor if not using VS2015
public T Resolve<T>() => (T)_factories[typeof(T)]();
}
class Program
{
static void Main(string[] args)
{
var container = new IocContainer();
container.Register<ISomeService>(() => new SomeService());
// ...
var service = container.Resolve<ISomeService>();
}
}
Now, where I'm doing container.Register<ISomeService>(() => new SomeService()), the covariance of Func delegates comes into play on two levels:
I can pass in a Func<SomeService> and it is assignable where a Func<ISomeService> is expected with no problems, because a SomeService is a ISomeService
Inside the Register method, a Func<T> can be assigned where a Func<object> is expected with no problems, because any reference type is an object
If a Func<SomeService> wasn't assignable to a Func<ISomeService>, or Func<ISomeService> wasn't assignable to a Func<object> (via covariance), this example wouldn't work.
You are right, it is not common an event to return with a value, it's kinda convention (actually it is more than convention: see extra reading #2). However delegates are not only for events, basically they are the .NET version of the near half century old C style "pointer to a function" (C terminology).
To leave the mystery left on events and delegates and listeners (java) in control flow concept they are just simple callbacks, so it is completely reasonable if they have return value.
So from this callback point of view:
Say I would like to process animals. I would like to use a function pointer (I mean: delegate or lambda) to do a part of this processing. Lets call it FeedAnimal. I would like to have an other skeleton method which calls this feed method, lets call it CareAnimal. I would like to plugin the feed algorithm to the care algorithm with run time variable mode, so the Care will have a delegate parameter: feed. After feeding the feed method returns an animal.
Now the point: The feed will have different implementations for Dog and Cat, one returns with Dog and the other returns with Cat.... and the Care() method accepts a delegate parameter which returns with Animal.
[Extra reading #1]: This kind of polymorphic implementation is the not OOP polymorphism implementaion. In OOP you can achieve similar with virtual method overloads.
[Extra reading #2]: The really disturbing thing about delegates (and events) that they are multicast delegates I mean one single delegate (which is a multicast delegate by default) can contain many method entry point. When it is invoked then all contained methods invoked in a cycle in not specified order. However there will be one return value in case the signature is not void. Of course this is confusing, so we safely say: If we use the multicast feature of delegates (or events) then it makes no sense other signature than void return.
Events are typically multicast, this comes from the Publisher/Subscriber DP metaphore: Many subscriber (handler) can subscribe (+=) to the publishers publication without knowing anything about each other.
Well, if you look at the declaration of the Func<T, TResult> Delegate.
public delegate TResult Func<in T, out TResult>(
T arg
)
You can see that the type of the input parameter is contravariant but the type of the result or return value is covariant.
The familiar Linq extension Select, has an overload that accepts this delegate.
Additionally, note that the return type of Select is IEnumerable<T>,
that is a covariant interface, i.e.
public IEnumerable<out T>
{
\\ ...
}
Now consider the types,
abstract class Mammal
{
}
and
class Dog : Mammal
{
}
I can declare an instance of the delegate.
var doItToMammals = new Func<Mammal, Mammal>(mammal => mammal);
I can pass this delegate to Select without variance.
IEnumerable<Mammal> mammals = new List<Mammal>().Select(doItToMammals);
Now, because the input of the function is contravariant, I can do
IEnumerable<Mammal> mammals = new List<Dog>().Select(doItToMammals);
Now here's the point, because the result is covariant, I can do
IEnumerable<Dogs> dogs = new List<Dog>().Select<Dog, Dog>(doItToMammals);
Let's have the following code (type-safe stubs for jQuery):
public interface IjQueryPromise { }
public interface IjQueryPromise<TResult> : IjQueryPromise { }
public static class jQueryPromiseEx
{
public static T Done<T>(this T t, params Action[] doneCallbacks)
where T : IjQueryPromise { return t; }
public static T Done<T, TResult>(this T t, params Action<TResult>[] doneCallbacks)
where T : IjQueryPromise<TResult> { return t; }
}
Using this code, I am trying to allow calling:
Done() with callback without arguments either on IjQueryPromise or IjQueryPromise<TResult>
Done() with callback with one argument of type TResult on IjQueryPromise<TResult>.
But since C# (v5.0) is unable to overload on generic constraints, passing lambda like:
(r) => DoSomething(r)
will produce compiler error:
Delegate 'System.Action' does not take 1 arguments.
I am implementing the methods as extension methods to return the type of the object on which the function is called.
The only idea what I have is automatically inline the code inside the interfaces and all their implementations.
Is it possible solve this in C# some better way?
Or does already exist a tool that do the inlining?
EDIT: I am designing the API for developers. I know that I can cast to delegate, but I do not want the developers (users of the API) to be forced to do the cast every time.
This isn't an issue with overload resolution.
It has nothing to do with a conflict with the other overload.
This is an issue with type inference. Your second overload won't be able to infer the type of TResult if you don't indicate the type of the parameter for the lambda, or the type of the entire delegate.
This is easy enough to see by simply removing the first overload from your application entirely. All that will do is change the error message from what you're getting to one saying that type inference has failed.
One way that you can both allow type inference and actually not provide any of the type information elsewhere (i.e typing the type out for the lambda parameter) would be to go down to just one generic argument:
public static IjQueryPromise<T> Done<T>(this IjQueryPromise<T> t,
params Action<T>[] doneCallbacks)
{ return t; }
The problem is that c# cannot infer the type of the argument in the anonymous method.
it will work if you declare the argument type this way;
IjQueryPromise<int> promise;
promise.Done( (int r) => DoSomething(r) ); // This should work as expected
I don't know if this is possible in C#. But here's what I'm trying to do:
An interface that declares a method with a completion block / callback / lambda / whatever you want to call it. Seems simple enough. But, here's a first attempt:
namespace N {
interface MyInterface {
delegate void CompletionBlock();
void doSomething(CompletionBlock completionBlock);
}
}
But interfaces can't declare delegates. Ok, how about this?
namespace N {
public delegate void CompletionBlock();
interface MyInterface {
void doSomething(CompletionBlock completionBlock);
}
}
Sure that works, but now, say I declare another type of CompletionBlock, one which takes an argument for instance. I can't call the type CompletionBlock because it'll clash with the above type, if inside the same namespace.
Then there's Action and Func. But even Action takes a parameter, and I want no parameters. So Action doesn't seem like a viable candidate. Really, all I want, is a way of inlining the concept of "anonymous block as long as the signature is void(void). Something like this:
namespace N {
interface MyInterface {
void doSomething(typeof(()=>) completionBlock);
}
}
But lambdas don't really have a type in C#. Do they at least have signatures?
Basically, is there any way around this?
In Objective-C, for instance, blocks are of type NSBlock, even though their signatures themselves are not easily accessible, but one can create a method that takes a block with a specific signature. For instance:
- (void)doSomething:(void(^)(void))completionBlock
Would be a method that takes a block with no parameters and no return type, and you'd call the method like so, for instance:
[obj doSomething:^(){your block code}];
Then there's Action and Func. But even Action takes a parameter, and I want no parameters. So Action doesn't seem like a viable candidate.
If you use Action (not Action<T>), it does not take parameters.
namespace N {
interface MyInterface {
void doSomething(Action completionBlock);
}
}
This allows you to write:
yourInstance.doSomething(() => DoWhatever(foo));
Or, if DoWhatever is void DoWhatever(), just:
yourInstance.doSomething(DoWhatever);
Use Action<T> or Func<TResult> or one of their siblings or just Action in your case.
Action<...> don't return anything where as Func<..., TResult> do.