Why won't this cast work? - c#

I have the following code:
var commitmentItems = new List<CommitmentItem<ITransaction>>();
commitmentItems.Add(new CapitalCallCommitmentItem());
And I get the following error:
Argument '1': cannot convert from 'Models.CapitalCallCommitmentItem' to
'Models.CommitmentItem<Models.ITransaction>'
However, CapitalCallCommitmentItem inherits from CommitmentItem<CapitalCall>, and CapitalCall implements ITransaction. So why the error?
Here is a better example:
CapitalCall implements ITransaction
var test = new List<ITransaction>();
test.Add(new CapitalCall());
var test2 = new List<List<ITransaction>>();
test.Add(new List<CapitalCall>()); // error.

Because that would need CommitmentItem<CapitalCall> to be covariant so that it is assignable to CommitmentItem<ITransaction>, which it currently not supported.
C# 4 added support for co- and contravariance in interfaces, but not for classes.
Therefore, if you're using C# 4 and you can use an interface such as ICommitmentItem<> instead of CommitmentItem<>, you might be able to get what you want by using the new features of C# 4.

Let's shorten these names.
C = CapitalCallCommentItem
D = CommitmentItem
E = CapitalCall
I = ITransaction
So your question is that you have:
interface I { }
class D<T>
{
public M(T t) { }
}
class C : D<E> { }
class E : I { }
And your question is "why is this illegal?"
D<E> c = new C(); // legal
D<I> d = c; // illegal
Suppose that was legal and deduce an error. c has a method M which takes an E. Now you say
class F : I { }
Suppose it was legal to assign c to d. Then it would also be legal to call d.M(new F()) because F implements I. But d.M is a method that takes an E, not an F.
Allowing this feature enables you to write programs that compile cleanly and then violate type safety at runtime. The C# language has been carefully designed so that the number of situations in which the type system can be violated at runtime are at a minimum.

Understanding why this doesn't work can be kind of tricky, so here's an analogous example, replacing the classes in your code with some well-known classes from the framework to act as placeholders and (hopefully) illustrate the potential pitfalls of such desired functionality:
// Note: replacing CommitmentItem<T> in your example with ICollection<T>
// and ITransaction with object.
var list = new List<ICollection<object>>();
// If the behavior you wanted were possible, then this should be possible, since:
// 1. List<string> implements ICollection<string>; and
// 2. string inherits from object.
list.Add(new List<string>());
// Now, since list is typed as List<ICollection<object>>, our innerList variable
// should be accessible as an ICollection<object>.
ICollection<object> innerList = list[0];
// But innerList is REALLY a List<string>, so although this SHOULD be
// possible based on innerList's supposed type (ICollection<object>),
// it is NOT legal due to innerList's actual type (List<string>).
// This would constitute undefined behavior.
innerList.Add(new object());

Because "A is subtype of B" does not imply that "X<A> is a subtype of X<B>".
Let me give you an example. Assume that CommitmentItem<T> has a method Commit(T t), and consider the following function:
void DoSomething(CommitmentItem<ITransaction> item) {
item.Commit(new SomethingElseCall());
}
This should work, since SomethingElseCall is a subtype of ITransaction, just like CapitalCall.
Now assume that CommitmentItem<CapitalCall> were a subtype of CommitmentItem<ITransaction>. Then you could do the following:
DoSomething(new CommitmentItem<CapitalCall>());
What would happen? You'd get a type error in the middle of DoSomething, because a SomethingElseCall is passed where a CapitalCall was expected. Thus, CommitmentItem<CapitalCall> is not a subtype of CommitmentItem<ITransaction>.
In Java, this problem can be solved by using the extends and super keywords, cf. question 2575363. Unfortunately, C# lacks such a keyword.

Note - I think Lucero and Eric Lippert himself have provided better direct answers to the question, but I think this is still valuable supplementary material.
Because C# 3.0 doesn't support covariance or contravariance of generic arguments. (And C# 4.0 has limited support for interfaces only.) See here for an explanation of covariance and contravariance, and some insight into the thinking that went on as the C# team were looking at putting this features into C# 4.0:
Covariance and contravariance in C#, part 1
Covariance and Contravariance in C#, Part Two: Array Covariance
Covariance and Contravariance in C#, Part Three: Method Group Conversion Variance
Covariance and Contravariance in C#, Part Four: Real Delegate Variance
Covariance and Contravariance In C#, Part Five: Higher Order Functions Hurt My Brain
Actually, he just keeps writing and writing! Here's everything he's tagged with "covariance and contravariance".

Related

Why type-safe is one the major benefits of using generics in C#?

When I was learning C# generics, some articles mentioned using generics is type-safe during execution by preventing the usage of data whose type is different from the one used in the declaration.
Link
I dont get why this should be an issue, if type is wrong shouldn't it crashed when build?
I'm curious about when and how this kind of problem could happen.
I'm curious about when and how this kind of problem could happen.
Basically, when using types that don't support generics but could. The classic example is probably ArrayList - the pre-generics equivalent of List<T>. ArrayList.Add just accepts object, so you can add anything into it - but typically code assumes just a specific type. So for example:
var people = new ArrayList();
people.Add(new Person("Jon"));
// ... later in the code
foreach (string name in people)
{
Console.WriteLine(name);
}
That crashes with a ClassCastException, because the list contains a Person reference, which is then implicitly cast to a string reference. That wouldn't happen with generics, where you'd have either a List<Person> or a List<string>, and spot errors at compile-time.
Generics are indeed type safe in compile time. I'd say that article in the sentence:
Client code that uses generics is type-safe during execution by
preventing the usage of data whose type is different from the one used
in the declaration
is referring to the implicit benefit of eliminating runtime invalid cast exceptions.
Generics provide type safety during compile-time, meaning you can't compile your code if the generic constraint is violated. And that is almost always preferable over a runtime exception.
void DoSomething<T>(T foo) where T : FooBase { }
If I try now to write code like this:
var myBar = new Bar(); // Does not inherit from FooBase
DoSomething(myBar);
Then I get this:
error CS0311: The type 'Bar' cannot be used as type parameter 'T' in the generic type or method 'DoSomething(T)'. There is no implicit reference conversion from 'Bar' to 'FooBase'.
And this happens during compile time. Perfect.
You might have also seen generics without any constraint:
void DomSomething<T>(T foo);
This will go a bit away from your original question, but one could ask what is the benefit over let's say: DoSomething(object obj). And here we have a difference between value types and reference types - namely boxing and unboxing happens when using the version with object.
So generics can also have some performance benefits, next to the type safety and reusability aspect.
One of the major benefits of generics in not just type-safety as is, but allowing writing generalized code while still maintaining type-safety and without degrading performance for value-types. For example we can generalize over collection of interface:
public interface IHaveId { int Id {get;}}
public T GetOrAddById<T>(IList<T> col, int id, T val) where T : class, IHaveId
{
var item = col.FirstOrDefault(x => x.Id == id);
if (item == null)
{
item = val;
col.Add(item);
}
return item;
}
Now you can't pass anything that does not implement the concrete interface.
Before the generics the only way of having generalized collection would be something like ArrayList (which can be compared to List<object>), so user could put anything in it without any type-safety.

Generic interface type inference weirdness in c#

C# cannot infer a type argument in this pretty obvious case:
public void Test<T>(IEnumerable<KeyValuePair<string, T>> kvp)
{
Console.WriteLine(kvp.GetType().Name + ": KeyValues");
}
Test(new Newtonsoft.Json.Linq.JObject());
The JObject type clearly implements IEnumerable<KeyValuePair<string, JToken>>, but I get the following error:
CS0411: The type arguments for method cannot be inferred from the usage.
Why does this happen?
UPD: To the editor who marked this question as duplicate: please note how my method's signature accepts not IEnumerable<T>, but IEnumerable<KeyValuePair<string, T>>. The JObject type implements IEnumerable twice, but only one of the implementations matches this constraint - so there should be no ambiguity.
UPD: Here's a complete self-contained repro without JObject:
https://gist.github.com/impworks/2eee2cd0364815ab8245b81963934642
Here's a simpler repro:
interface I<T> {}
class X<T> {}
class Y {}
class Z {}
class C : I<X<Y>>, I<Z> {}
public class P
{
static void M<T>(I<X<T>> i) { }
public static void Main()
{
M(new C());
}
}
Type inference fails. You ask why, and why questions are always difficult to answer, so let me rephrase the question:
What line of the specification disallows this inference?
I have my copy of the C# 3 specification at hand; the line there is as follows
V is the type we are inferring to, so I<X<T>> in this case
U is the type we are inferring from, so C in this case
This will be slightly different in C# 4 because I added covariance, but we can ignore that for the purposes of this discussion.
... if V is a constructed type C<V1, … Vk> and there is a unique set of types U1, … Uk such that an implicit conversion exists from U to C<U1, … Uk> then an exact inference is made from each Ui to the corresponding Vi. Otherwise no inferences are made.
Notice the word unique in there. There is NOT a unique set of types such that C is convertible to I<Something> because both X<Y> and Z are valid.
Here's another non-why question:
What factors were considered when the design team made this decision?
You are right that in theory we could detect in your case that X<Y> is intended and Z is not. If you would care to propose a type inference algorithm that can handle non-unique situations like this that never makes a mistake -- remember, Z could be a subtype or a supertype of X<Y> or X<Something Else> and I could be covariant -- then I am sure that the C# team would be happy to consider your proposal.
We had that argument in 2005 when designing the C# 3 type inference algorithm and decided that scenarios where one class implements two of the same interface were rare, and that dealing with those rare situations created considerable complications in the language. Those complications would be expensive to design, specify, implement and test, and we had other things to spend money and effort on that would have bigger impact.
Also, we did not know when we made C# 3 whether or not we would be adding covariance in C# 4. We never want to introduce a new language feature that makes a possible future language feature impossible or difficult. It is better to put restrictions in the language now and consider removing them later than to do a lot of work for a rare scenario that makes a common scenario difficult in the next version.
The fact that I helped design this algorithm and implemented it multiple times, and completely did not remember this rule at first should tell you how often this has come up in the last 13 years. Hardly at all. It is very rare for someone to be in your particular boat, and there is an easy workaround: specify the type.
A question which you did not ask but comes to mind:
Could the error message be better?
Yep. I apologize for that. I did a lot of work making overload resolution error messages more descriptive for common LINQ scenarios, and I always wanted to go back and make the other type inference error messages more clear. I wrote the type inference and overload resolution code to maintain internal information explaining why a type had been inferred or an overload had been chosen or rejected, both for my own debugging purposes and to make better error messages, but I never got around to exposing that information to the user. There was always something higher priority.
You might consider entering an issue at the Roslyn GitHub site suggesting that this error message be improved to help users diagnose the situation more easily. Again, the fact that I didn't immediately diagnose the problem and had to go back to the spec is indicative that the message is unclear.
Problem is following.
If you don't specify type then it will try to infer automatically but if it get confuse then it throw specified exception.
In your case JObject has implemented interface IEnumerable<KeyValuePair<string, JToken>>.
Also JObject implemented JContainer and it also implemented IEnumerable< JToken>.
So when it is specified for T it is confuse between IEnumerable<JToken> and IEnumrable<KeyValuePair<string, JToken>>.
I suspect that when people who designed C# were thinking about how compiler would infer the type for a generic type parameter they thought about potential issues with that.
Consider the following scenario:
class MyClass : JObject, IEnumerable<KeyValuePair<string, int>>
{
public IEnumerator<KeyValuePair<string, int>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Foo : MyClass { }
class FooBar : Foo { }
public void Test<T>(IEnumerable<KeyValuePair<string, T>> kvp)
{
Console.WriteLine(kvp.GetType().Name + ": KeyValues");
}
var fooBar = new FooBar();
Test(fooBar);
Which type should the T be inferred to? int, or JToken ?
Also how complex should the algorithm be ?
Presumably that's why compiler only infers the type when there is no chance for ambiguity. It was designed this way and not without a reason.

C# Variance return type

I am new to C# and having some real problems trying to apply variance restrictions to template types. Maybe it's just not possible the only "Where" clause examples I can find from my research are more based on going the other direction (ie. "Is assignable from"). I've listed the Scala function I'm trying to emulate - the point is to insure that T is assignable to U (ie. T<:U) so the return value is a U no matter what. Any help or tips on C# variance is appreciated, thank you
interface Option<out T> // where T : class
{
T GetUnsafe();
Option<X> map<X>(Func<object,Option<X>> f);
U GetOrElse<U>(U u) where T:U ; //What is wrong here,how do I get U:>T ?
bool IsSome { get; }
}
Example from Scala Option[A]
final def getOrElse[B >: A](default: ⇒ B): B
As an update, here's a working version as a Static function - I just can't figure out if it's possible as a method
static class Option
{
public static U GetOrElse<T, U>(Option<T> o, U defAns) where T : U
{
if (o.IsSome) return o.GetUnsafe(); else return defAns;
}
First of all you seem to mix "generic variance" with "generic type constraints". Yes, C# unlike Java or Scala only supports inheritance-related type constraints in one direction: you can specify base class (but you can do something that neither Scala nor Java support such as new constraint). See where (generic type constraint) (C# Reference) for some details. And since T is defined in the outer scope you can't put additional constraints to it in the inner scope. This is the reason why your example doesn't compile. Your second example with a static method compiles because C# compiler is smart enough to re-order generic types in your declaration so that it looks like you define constraint (for T) using already known type (U).
I'm not sure what is the real life usage of that design of getOrElse Scala method given the fact that Option is covariant i.e. if you want to get value of type B even though its actual type is A just declare your var as having type Option[B]. So I think it wouldn't be a big loss to not copy this bit of logic.
Generally I don't think you can easily copy such a code exactly preserving behavior from Scala to C# but for this particular case where this method has only one fixed implementation that you don't need to override, you can extend you static trick to use extension methods:
public static class OptionHelper
{
public static U GetOrElse<T, U>(this Option<T> o, U defAns)
where T : U
{
if (o.IsSome) return o.GetUnsafe(); else return defAns;
}
}
Because of additional this keyword before argument you can use it as if it was defined in the interface itself (a bit similar to default methods in Java 8 and what you can get using implicit conversions in Scala):
Option<string> o = ..;
object value = o.GetOrElse(new object());

Why does a method invocation expression have type dynamic even when there is only one possible return type?

Inspired by this question.
Short version: Why can't the compiler figure out the compile-time type of M(dynamic arg) if there is only one overload of M or all of the overloads of M have the same return type?
Per the spec, §7.6.5:
An invocation-expression is dynamically bound (§7.2.2) if at least one of the following holds:
The primary-expression has compile-time type dynamic.
At least one argument of the optional argument-list has compile-time type dynamic and the primary-expression does not have a delegate type.
It makes sense that for
class Foo {
public int M(string s) { return 0; }
public string M(int s) { return String.Empty; }
}
the compiler can't figure out the compile-time type of
dynamic d = // dynamic
var x = new Foo().M(d);
because it won't know until runtime which overload of M is invoked.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
I'm looking to understand why the spec doesn't allow the compiler to type these expressions statically at compile time.
UPDATE: This question was the subject of my blog on the 22nd of October, 2012. Thanks for the great question!
Why can't the compiler figure out the compile-type type of M(dynamic_expression) if there is only one overload of M or all of the overloads of M have the same return type?
The compiler can figure out the compile-time type; the compile-time type is dynamic, and the compiler figures that out successfully.
I think the question you intended to ask is:
Why is the compile-time type of M(dynamic_expression) always dynamic, even in the rare and unlikely case that you're making a completely unnecessary dynamic call to a method M that will always be chosen regardless of the argument type?
When you phrase the question like that, it kinda answers itself. :-)
Reason one:
The cases you envision are rare; in order for the compiler to be able to make the kind of inference you describe, enough information must be known so that the compiler can do almost a full static type analysis of the expression. But if you are in that scenario then why are you using dynamic in the first place? You would do far better to simply say:
object d = whatever;
Foo foo = new Foo();
int x = (d is string) ? foo.M((string)d) : foo((int)d);
Obviously if there is only one overload of M then it is even easier: cast the object to the desired type. If it fails at runtime because the cast it bad, well, dynamic would have failed too!
There's simply no need for dynamic in the first place in these sorts of scenarios, so why would we do a lot of expensive and difficult type inference work in the compiler to enable a scenario we don't want you using dynamic for in the first place?
Reason two:
Suppose we did say that overload resolution has very special rules if the method group is statically known to contain one method. Great. Now we've just added a new kind of fragility to the language. Now adding a new overload changes the return type of a call to a completely different type -- a type which not only causes dynamic semantics, but also boxes value types. But wait, it gets worse!
// Foo corporation:
class B
{
}
// Bar corporation:
class D : B
{
public int M(int x) { return x; }
}
// Baz corporation:
dynamic dyn = whatever;
D d = new D();
var q = d.M(dyn);
Let's suppose that we implement your feature requiest and infer that q is int, by your logic. Now Foo corporation adds:
class B
{
public string M(string x) { return x; }
}
And suddenly when Baz corporation recompiles their code, suddenly the type of q quietly turns to dynamic, because we don't know at compile time that dyn is not a string. That is a bizarre and unexpected change in the static analysis! Why should a third party adding a new method to a base class cause the type of a local variable to change in an entirely different method in an entirely different class that is written at a different company, a company that does not even use B directly, but only via D?
This is a new form of the Brittle Base Class problem, and we seek to minimize Brittle Base Class problems in C#.
Or, what if instead Foo corp said:
class B
{
protected string M(string x) { return x; }
}
Now, by your logic,
var q = d.M(dyn);
gives q the type int when the code above is outside of a type that inherits from D, but
var q = this.M(dyn);
gives the type of q as dynamic when inside a type that inherits from D! As a developer I would find that quite surprising.
Reason Three:
There is too much cleverness in C# already. Our aim is not to build a logic engine that can work out all possible type restrictions on all possible values given a particular program. We prefer to have general, understandable, comprehensible rules that can be written down easily and implemented without bugs. The spec is already eight hundred pages long and writing a bug-free compiler is incredibly difficult. Let's not make it more difficult. Not to mention the expense of testing all those crazy cases.
Reason four:
Moreover: the language affords you many opportunities to avail yourself of the static type analyzer. If you are using dynamic, you are specifically asking for that analyzer to defer its action until runtime. It should not be a surprise that using the "stop doing static type analysis at compile time" feature causes static type analysis to not work very well at compile time.
An early design of the dynamic feature had support for something like this. The compiler would still do static overload resolution, and introduced a "phantom overload" that represents dynamic overload resolution only if necessary.
Blog post introducing phantom methods
Details on phantom methods
As you can see in the second post, this approach introduces a lot of complexity (the second article talks about how type inference would need to be modified to make the approach work out). I'm not surprised that the C# team decided to go with the simpler idea of always using dynamic overload resolution when dynamic is involved.
However, why can't the compiler figure out the compile-time type if M has only one overload or all of the overloads of M return the same type?
The compiler could potentially do this, but the language team decided not to have it work this way.
The entire purpose of dynamic is to have all expressions using dynamic execute with "their resolution is deferred until the program is run" (C# spec, 4.2.3). The compiler explicitly does not perform static binding (which would be required to get the behavior you want here) for dynamic expressions.
Having a fallback to static binding if there was only a single binding option would force the compiler to check this case - which was not added in. As for why the language team didn't want to do it, I suspect Eric Lippert's response here applies:
I am asked "why doesn't C# implement feature X?" all the time. The answer is always the same: because no one ever designed, specified, implemented, tested, documented and shipped that feature.
I think the case of being able to statically determine the only possible return type of a dynamic method resolution is so narrow that it would be more confusing and inconsistent if the C# compiler did it, rather than having across the board behavior.
Even with your example, what if Foo is part of a different dll, Foo could be a newer version at runtime from a binding redirect with additional M's that have a different return type, and then the compiler would have guessed wrong because the runtime resolution would return a different type.
What if Foo is an IDynamicMetaObjectProvider d might not match any of the static arguments and thus it would fall back on it's dynamic behavior which could possibly return a different type.

Strongly typed collection Implicit and explicit cast

public void Foo (IEnumerable<object> objects)
{
}
var strings = new List<string>{"first", "second", "third"};
Foo(strings); // Compilation Error.
Foo(strings.Cast<object>()); // O.k.
Why the first call to Foo doesn't compile? string derived from object.
If I can cast the list to object and it's compiled, why the compiler doesn't do it by his own?
The first call compiles in .NET 4.0.
In previous versions, the generic types have to match exactly.
I suggest reading the blogs posts of Eric Lippert regarding variance (covariance and contravariance).
You wan't to look up co-variance and contra-variance.
It's new feature in .NET 4.0
Generics are strict in the sense that you cannot assign a collection of a derived type to a collection of a supertype. You must provide the exact type used to instantiate the collection.
Because it cannot know what you want to do. Same reason why the following line does not compile:
string s = new object();
To force an "unsafe" type cast on the user would be too much liberty given to the compiler.

Categories