Combining delegates and contravariance - c#

The article states the following: http://msdn.microsoft.com/en-us/library/dd799517.aspx
Variance does not apply to delegate combination. That is, given two delegates of types Action<Derived> and Action<Base> (Action(Of Derived) and Action(Of Base) in Visual Basic), you cannot combine the second delegate with the first although the result would be type safe. Variance allows the second delegate to be assigned to a variable of type Action<Derived>, but delegates can combine only if their types match exactly.
Action<B> baction = (taret) => { Console.WriteLine(taret.GetType().Name); };
Action<D> daction = baction;
Action<D> caction = baction + daction;
In the above code baction and daction take different parameters. But still I am able to combine them.
What am I missing?
TIA.

The documentation is not clear, I agree.
The problem is that the runtime types of two combined delegates must match. Which means that there are scenarios where the compile time types match, but the runtime types do not.
Consider for example:
Func<string> f1 = ()=>"";
Func<object> f2 = ()=>null;
Func<object> f3 = f1; // legal in C# 4 because of covariance
Func<object> f4 = f2 + f3;
That's legal at compile time; you're adding two delegates of the same compile-time type. But at runtime it will fail because the runtime requires that the runtime types exactly match.
This is an unfortunate hole in the CLR type system. I'm hoping we can get it fixed some day, but no promises.

Related

Why C# Func<int> cannot be assigned to Func<object>?

I've studied Covariant and Contravariant in C#.
and below my code has an error.
object a = new object();
int b = 10;
a = b; // not error
Func<object> acO = () => new object();
Func<int> acI = () => 1;
acO = acI; // error
Error Message:
Cannot implicitly convert type 'System.Func' to type 'System.Func'.
I thought that if int -> object is possible, Func -> Func will be possible.
but it is not.
I think value type will be copied to use when it is returned unlike reference type(object) and it can cause unintentional operation(like exception). Is my guess correct?
I'm looking forward to your wise answers.
Thank you for reading.
From the Variance in Delegates (C#) docs:
Variance for generic type parameters is supported for reference types only.
A nice blog post diving into the topic by Eric Lippert:
All the built-in reference conversions are identity-preserving. This is why covariant and contravariant conversions of interface and delegate types require that all varying type arguments be of reference types. To ensure that a variant reference conversion is always identity-preserving, all of the conversions involving type arguments must also be identity-preserving. The easiest way to ensure that all the non-trivial conversions on type arguments are identity-preserving is to restrict them to be reference conversions.

Why isn't there an implicit typeof?

I think I understand why this small C# console application will not compile:
using System;
namespace ConsoleApp1
{
class Program
{
static void WriteFullName(Type t)
{
Console.WriteLine(t.FullName);
}
static void Main(string[] args)
{
WriteFullName(System.Text.Encoding);
}
}
}
The compiler raises a CS0119 error: 'Encoding' is a type which is not valid in the given context. I know that I can produce a Type object from its name by using the typeof() operator:
...
static void Main(string[] args)
{
WriteFullName(typeof(System.Text.Encoding));
}
...
And everything works as expected.
But to me, that use of typeof() has always seemed somewhat redundant. If the compiler knows that some token is a reference to a given type (as error CS0119 suggests) and it knows that the destination of some assignment (be it a function parameter, a variable or whatever) expects a reference to a given type, why can't the compiler take it as an implicit typeof() call?
Or maybe the compiler is perfectly capable of taking that step, but it has been chosen not to because of the problems that might generate. Would that result in any ambiguity/legibility issues that I cannot think of right now?
If the compiler knows that some token is a reference to a given type (as error CS0119 suggests) and it knows that the destination of some assignment (be it a function parameter, a variable or whatever) expects a reference to a given type, why can't the compiler take it as an implicit typeof() call?
First off, your proposal is that the compiler reason both "inside to outside" and "outside to inside" at the same time. That is, in order to make your proposed feature work the compiler must both deduce that the expression System.Text.Encoding refers to a type and that the context -- a call to WriteFullName -- requires a type. How do we know that the context requires a type? The resolution of WriteFullName requires overload resolution because there could be a hundred of them, and maybe only one of them takes a Type as an argument in that position.
So now we must design overload resolution to recognize this specific case. Overload resolution is hard enough already. Now consider the implications on type inference as well.
C# is designed so that in the vast majority of cases you do not need to do bidirectional inference because bidirectional inference is expensive and difficult. The place where we do use bidirectional inference is lambdas, and it took me the better part of a year to implement and test it. Getting context-sensitive inference on lambdas was a key feature that was necessary to make LINQ work and so it was worth the extremely high burden of getting bidirectional inference right.
Moreover: why is Type special? It's perfectly legal to say object x = typeof(T); so shouldn't object x = int; be legal in your proposal? Suppose a type C has a user-defined implicit conversion from Type to C; shouldn't C c = string; be legal?
But let's leave that aside for a moment and consider the other merits of your proposal. For example, what do you propose to do about this?
class C {
public static string FullName = "Hello";
}
...
Type c = C;
Console.WriteLine(c.FullName); // "C"
Console.WriteLine(C.FullName); // "Hello"
Does it not strike you as bizarre that c == C but c.FullName != C.FullName ? A basic principle of programming language design is that you can stuff an expression into a variable and the value of the variable behaves like the expression, but that is not at all true here.
Your proposal is basically that every expression that refers to a type has a different behaviour depending on whether it is used or assigned, and that is super confusing.
Now, you might say, well, let's make a special syntax to disambiguate situations where the type is used from situations where the type is mentioned, and there is such a syntax. It is typeof(T)! If we want to treat T.FullName as T being Type we say typeof(T).FullName and if we want to treat T as being a qualifier in a lookup we say T.FullName, and now we have cleanly disambiguated these cases without having to do any bidirectional inference.
Basically, the fundamental problem is that types are not first class in C#. There are things you can do with types that you can only do at compile time. There's no:
Type t = b ? C : D;
List<t> l = new List<t>();
where l is either List<C> or List<D> depending on the value of b. Since types are very special expressions, and specifically are expressions that have no value at runtime they need to have some special syntax that calls out when they are being used as a value.
Finally, there is also an argument to be made about likely correctness. If a developer writes Foo(Bar.Blah) and Bar.Blah is a type, odds are pretty good they've made a mistake and thought that Bar.Blah was an expression that resolves to a value. Odds are not good that they intended to pass a Type to Foo.
Follow up question:
why is it possible with method groups when passed to a delegate argument? Is it because usage and mentioning of a method are easier to distinguish?
Method groups do not have members; you never say:
class C { public void M() {} }
...
var x = C.M.Whatever;
because C.M doesn't have any members at all. So that problem disappears. We never say "well, C.M is convertible to Action and Action has a method Invoke so let's allow C.M.Invoke(). That just doesn't happen. Again, method groups are not first class values. Only after they are converted to delegates do they become first class values.
Basically, method groups are treated as expressions that have a value but no type, and then the convertibility rules determine what method groups are convertible to what delegate types.
Now, if you were going to make the argument that a method group ought to be convertible implicitly to MethodInfo and used in any context where a MethodInfo was expected, then we'd have to consider the merits of that. There has been a proposal for decades to make an infoof operator (pronounced "in-foof" of course!) that would return a MethodInfo when given a method group and a PropertyInfo when given a property and so on, and that proposal has always failed as too much design work for too little benefit. nameof was the cheap-to-implement version that got done.
A question you did not ask but which seems germane:
You said that C.FullName could be ambiguous because it would be unclear if C is a Type or the type C. Are there other similar ambiguities in C#?
Yes! Consider:
enum Color { Red }
class C {
public Color Color { get; private set; }
public void M(Color c) { }
public void N(String s) { }
public void O() {
M(Color.Red);
N(Color.ToString());
}
}
In this scenario, cleverly called the "Color Color Problem", the C# compiler manages to figure out that Color in the call to M means the type, and that in the call to N, it means this.Color. Do a search in the specification on "Color Color" and you'll find the rule, or see blog post Color Color.

Generic class can product identical signature overloads? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generic methods and method overloading
Ok, I hit this one by accident... Giving this situation:
class Program {
static void Main( string[ ] args ) {
var obj = new gen<int>( );
Console.Write( obj[ 1 ] );
Console.ReadKey( );
}
}
class gen<T> {
public int this[ T i ] { get { return 2; } }
public int this[ int i ] { get { return 1; } }
}
It will always print 1. I would have expected for the compiler to complain, or the runtime to crash and burn and melt the CPU, but no, it is happy to print '1'
Of course I can make a choice to return either if I use any other type for the generic parameter. For giggles, I try using UInt as the generic type parmater, and I can differentiate between the calls, so the questions are:
Why C# does not freak out? Shouldn't Anders Hejlsberg feel a disturbance in the force?
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
I believe this is specified in section 7.5.3.2 of the C# 4 spec (Better Function Member).
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ [...]
A type parameter is less specific than a nontype parameter
[...]
So here, the member with the T parameter is less specific than the member with the int parameter.
Try to design your way out of this one simply by not overloading like this. It's hard for indexers of course, but you could always provide methods instead (or possibly as well, as a fall-back).
EDIT: Note that if you have overloaded methods where both are type parameters, the compiler will complain:
public class Foo<T1, T2>
{
public void Bar(T1 t1) {}
public void Bar(T2 t2) {}
}
...
Foo<int, int> foo = new Foo<int, int>();
foo.Bar(10); // Error
Here neither method is more specific.
How can I restrict a generic parameter from certain types? As in this T can be anything but ints (but long are OK)
This is really an entirely separate question, but basically you can't. You can constrain type parameters in various ways, but not by explicitly including and excluding types. See the MSDN page on constraints for more information.
As Eric Lippert says:
The C# specification says that when you have a choice between calling ReallyDoIt(string) and ReallyDoIt(string) – that is,
when the choice is between two methods that have identical signatures,
but one gets that signature via generic substitution – then we pick
the “natural” signature over the “substituted” signature.
Also this process described in C# spec 7.5.3.2 (Better function member):
In case the parameter type sequences {P1, P2, …, PN} and {Q1, Q2, …, QN} are equivalent (i.e. each Pi has an identity conversion to the corresponding Qi), the following tie-breaking rules are applied, in order, to determine the better function member.
If MP is a non-generic method and MQ is a generic method, then MP is better than MQ (as John pointed, this is true when you have generic method, not generic type)
...
Otherwise, if MP has more specific parameter types than MQ, then MP is better than MQ. Let {R1, R2, …, RN} and {S1, S2, …, SN} represent the uninstantiated and unexpanded parameter types of MP and MQ. MP’s parameter types are more specific than MQ’s if, for each parameter, RX is not less specific than SX, and, for at least one parameter, RX is more specific than SX:
A type parameter is less specific than a non-type parameter (this is your case - thus methods are not generic, and inferred parameter type equals to non-generic parameter type)
The C# compiler always chooses the more-specific versus the more-generic method if the call could fit in both =). That's why it doesn't freak out, he just follows his rules.
C# compiler doesn't freak out because both method are valid, and both can be called.
Here's an example that return "2":
Gen<Form> gen = new Gen<Form>();
textBox1.Text = gen[this].ToString();
Where "this" is a form. Of course, using an index accessor as an object instead of a number... Well, whatever, it works.
But like everybody else said, the compiler will prefer the explicit over the implicit.

Why is "dynamic" not covariant and contravariant with respect to all types when used as a generic type parameter?

I am wondering if dynamic is semantically equivalent to object when used as a generic type parameter. If so, I am curious why this limitation exists since the two are different when assigning values to variables or formal parameters.
I've written a small experiment in C# 4.0 to tease apart some of the details. I defined some simple interfaces and implementations:
interface ICovariance<out T> { T Method(); }
interface IContravariance<in T> { void Method(T argument); }
class Covariance<T> : ICovariance<T>
{
public T Method() { return default(T); }
}
class Contravariance<T> : IContravariance<T>
{
public void Method(T argument) { }
}
The interesting details of the experiment:
class Variance
{
static void Example()
{
ICovariance<object> c1 = new Covariance<string>();
IContravariance<string> c2 = new Contravariance<object>();
ICovariance<dynamic> c3 = new Covariance<string>();
IContravariance<string> c4 = new Contravariance<dynamic>();
ICovariance<object> c5 = new Covariance<dynamic>();
IContravariance<dynamic> c6 = new Contravariance<object>();
// The following statements do not compile.
//ICovariance<string> c7 = new Covariance<dynamic>();
//IContravariance<dynamic> c8 = new Contravariance<string>();
// However, these do.
string s = new Covariance<dynamic>().Method();
new Contravariance<string>().Method((dynamic)s);
}
}
The first two statements with c1 and c2 demonstrate that basic covariance and contravariance are working. I then use c3 and c4 to show that dynamic can be used as a generic type parameter in the same fashion.
The statements with c5 and c6 reveal that a conversion from dynamic to object is always valid. This isn't really too surprising, since object is an ancestor of all other types.
The final experiment with c7 and c8 is where I start to become confused. It implies that methods that return dynamic objects are not substitutes for methods that return string ones, and similarly that methods that accept string objects cannot take dynamic ones. The final two statements with the assignment and method call show this is clearly not the case, hence my confusion.
I thought about this a little, and wondered if this is to prevent programmers from using ICovariance<dynamic> as a stepping stone between type conversions that would result in run-time errors, such as:
ICovariance<dynamic> c9 = new Covariance<Exception>();
ICovariance<string> c10 = c9;
// While this is definitely not allowed:
ICovariance<string> c11 = new Covariance<Exception>();
However, this is unconvincing in the case of dynamic since we lose type-safety anyway:
dynamic v1 = new Exception();
string v2 = v1;
Put another way, the question is "Why does the semantics of dynamic differ between assignment and covariance/contravariance with generics?"
I am wondering if dynamic is semantically equivalent to object when used as a generic type parameter.
Your conjecture is completely correct.
"dynamic" as a type is nothing more than "object" with a funny hat on, a hat that says "rather than doing static type checking for this expression of type object, generate code that does the type checking at runtime". In all other respects, dynamic is just object, end of story.
I am curious why this limitation exists since the two are different when assigning values to variables or formal parameters.
Think about it from the compiler's perspective and then from the IL verifier's perspective.
When you're assigning a value to a variable, the compiler basically says "I need to generate code that does an implicit conversion from a value of such and such a type to the exact type of the variable". The compiler generates code that does that, and the IL verifier verifies its correctness.
That is, the compiler generates:
Frob x = (Frob)whatever;
But limits the conversions to implicit conversions, not explicit conversions.
When the value is dynamic, the compiler basically says "I need to generate code that interrogates this object at runtime, determines its type, starts up the compiler again, and spits out a small chunk of IL that converts whatever this object is to the type of this variable, runs that code, and assigns the result to this variable. And if any of that fails, throw."
That is, the compiler generates the moral equivalent of:
Frob x = MakeMeAConversionFunctionAtRuntime<Frob>((object)whatever);
The verifier doesn't even blink at that. The verifier sees a method that returns a Frob. That method might throw an exception if it is unable to turn "whatever" into a Frob; either way, nothing but a Frob ever gets written into x.
Now think about your covariance situation. From the CLR's perspective, there is no such thing as "dynamic". Everywhere that you have a type argument that is "dynamic", the compiler simply generates "object" as a type argument. "dynamic" is a C# language feature, not a Common Language Runtime feature. If covariance or contravariance on "object" isn't legal, then it isn't legal on "dynamic" either. There's no IL that the compiler can generate to make the CLR's type system work differently.
This then explains why it is that you observe that there is a conversion from, say, List<dynamic> to and from List<object>; the compiler knows that they are the same type. The specification actually calls out that these two types have an identity conversion between them; they are identical types.
Does that all make sense? You seem very interested in the design principles that underly dynamic; rather than trying to deduce them from first principles and experiments yourself, you could save yourself the bother and read Chris Burrows' blog articles on the subject. He did most of the implementation and a fair amount of the design of the feature.
for this one:
ICovariance<string> c7 = new Covariance<dynamic>();
reason is obvious, if it was possible then you could do:
c7.Method().IndexOf(...);
and it will definitely fail, except if dynamic is not string or has those method.
since (even after all the changes) c# is not dynamic language. Covariance is allowed only when it is definitely safe. You can of course shot into your feet and call IndexOf on dynamic variable, but you can't let users of your API to do it unintentionally. For example if you return such a ICovariance<string> with dynamic undercover calling code might fail!
Remember the rule, D is covariant to B if there is a cast from D to B. In this case there is no cast from dynamic to string.
But dynamic is covariant to object just because everything is derived from it.
Because dynamic and covariant/contravariant keywords are so new?
I would guess that you kind of answered your own question. Assignment type-safety is relaxed in assignment statements, because that's how dynamic works; it short-circuits compile-time type-checking so you can make assignments you EXPECT to work from objects the compiler has no clue about.
However, generic covariance/contravariance is rigidly controlled; without the use of the in/out keywords (which were also introduced alongside dynamic in C# 4.0) you couldn't convert either way. The generic parameters, even with co/contravariance allowed, require the types to be in the same branch of the inheritance hierarchy. A String is not a dynamic and a dynamic is not a string (though both are Objects and a dynamic may refer to what could be accessed as a string), so the generic type-checking inherent in the covariance/contravariance checks fails, while OTOH, the compiler is expressly told to ignore most non-generic operations involving dynamic.
"Why does the semantics of dynamic differ between assignment and covariance/contravariance with generics?"
The answer is that when using generics you are abstracted from the data type itself. However, it also implies that generic is generic enough that all types will share the same functionality.
So if you have 'ICovariance c9 = new Covariance();` both dynamic and exception do not have the same functionalities (as base types). More over, the compiler doesn't have a clue as to how to convert from dynamic to exception (even though they both inherit from object).
If there was an explicit inheritance hierarchy between dynamic and Exception (other than object), than this would be somewhat ok.
The reason somewhat is because you can downcast, but not upcast. EG, if exception inherits from dynamic, than it would be fine. If dynamic inherits from Exception it would be an upcast kinda deal and that would not be ok, since there could be the condition where the 'dynamic's data is not present inException`.
.NET has these explicit typecasts built in, and you can see them in action in the System.Convert object. However, types that are super specific cannot be easily implicitly or explicitly casted between one another without custom code. And this is one of the reasons why having multi-types fails (as is the case with 'ICovariance c9 = new Covariance();` ). This is also built to preserve type safety.

Is the C# compiler unable to infer method type parameters by expected return type?

This seems odd to me, but I remember a thread where Eric Lippert commented on the inability (by design, or at least convention, I think) of C# to overload methods based on return type, so perhaps it's in some convoluted way related to that.
Is there any reason this does not work:
public static T Test<T>() where T : new()
{
return new T();
}
// Elsewhere
SomeObject myObj = Test();
But this does:
var myObj = Test<SomeObject>();
From a certain perspective, they're both fine, in that you're not Repeating Yourself (in a very small way), but is this just a different pass of the compiler?
First off, this is "overloading based on return type":
void M(int x){...}
int M(int x){...}
string M(int x){...}
The declarations are not legal; you can't overload a method based on return type because the return type is not part of the signature, and the signature has to be unique.
What you are talking about is method type inference based on the method's return type. We don't support that either.
The reason is because the return type might be what you are trying to figure out.
M(Test());
What's the return type of Test? That depends on which overload of M we choose. What overload of M do we choose? That depends on the return type of Test.
In general, C# is designed so that every subexpression has a type, and the types are worked out from the "inside" towards the "outside", not from the outside to the inside.
The notable exceptions are anonymous functions, method groups, and null:
M(x=>x+1)
What's the type of x=>x+1? It depends on which overload of M is called.
M(N); // N is a method group
what's the type of N? Again, it depends on which overload of M is called.
And so on. In these cases we do reason from "outside" to "inside".
Type inference involving lambdas is extremely complicated and was difficult to implement. We don't want to have that same complication and difficulty throughout the compiler.
Except for typeless expressions (null, method groups, and lambda expressions), the type of an expression must be statically determinable by the expression itself, regardless of context.
In other words, the type of an expression Test() cannot depend on what you're assigning it to.
Check C# Language Specification §7.5.2, the declaring type of a variable is not an attestation for type inference, and obviously it shouldn't be. Consider the following code:
Base b = Test<Derived>();
Derived d = Test<Derived>();
The return type of the method probably differs from the declaring type of the variable, since we have implicit convert in C#.
Type inference by the compiler doesn't use the "expected type" of an assignment as part of the logic.
So, the "scope of consideration" for type inference is not this:
SomeObject myObj = Test();
but this:
Test();
And, there are no clues here as to the expected type.
If you want an example of why the type of an expression needs to be able to be determined by the expression itself, consider the following two cases:
We don't use the return value at all - we're just calling the method for its side-effects.
We pass the return value directly into an overloaded method
Using the "expected type" of the return value when it comes to generic type resolution would introduce a whole whack of additional complexity into the compiler, and all you've gained is that sometimes you need to explicitly specify the type and sometimes you don't, and whether you need to or not can change based on unrelated changes elsewhere in the code.

Categories

Resources