[Discussion] Default values in a generic context #2601
Replies: 5 comments
-
No, they are not. One reason for that is that different languages handle operators differently.
Overloading is resolved at compile time (with the exception of
This is also not quite true: generic methods are JITted only once for all reference types.
I don't understand, why would that make it okay? I think it's never okay for
That does look like a bug to me. Based on dotnet/roslyn#24913, I think that code should also produce a compile-time error, just like the One more question: why do you want this work, when |
Beta Was this translation helpful? Give feedback.
-
This PR was merged one year ago, why is this bug still in our compilers? Do we need to update something? Or do I need to file a new bug somewhere?
That was just speculation to see what was going on, haven't really read up on operators.
This is fine, since all reference types have a default of null, it's not going to get in the way.
If you put these two expressions side-by-side, and ask me to pick one, I'm definitely going with the one with the equal sign in it. The syntax is cleaner, the intention is clear. I just got an idea on what would make this possible. Generic constraints on operators. i.e. public void Foo<T>(T value) where T : ==
{
if (value == default(T))
} Problem solved? |
Beta Was this translation helpful? Give feedback.
-
I think an issue should be filed at dotnet/roslyn about this, yes.
Because there is no reasonable sequence of IL instructions that does the right thing.
You're right. But having some way to achieve what you want, even if it's not ideal, makes the feature less useful to have.
I think that's a good idea, and it's actually being worked on, in an even more general form called "shapes": #164. If shapes were implemented, I think you would get what you wanted. |
Beta Was this translation helpful? Give feedback.
-
Note that this isn't so much about default values at all - it's about the equality operator.
For reference types, There's a very good reason that user-defined operators are static methods in C# (whereas many languages make them virtual instance methods), and that is to avoid problems where Value types are similar, except that So the JIT knows nothing about Now you can see the problem. In a generic method, there's no way for the compiler to know what types are involved at compile-time, and so it can never find a suitable user-defined So in an unconstrained generic method (i.e. there's no If you add the constraint If you add the constraint Hopefully that explains why things are the way that they are. Primarily the issue is that operator resolution is done by the compiler, but generic methods are expanded by the JIT. Note that C# does have an If you want to do a reference comparison of two generic variables (and always return false if they are value types), then use I agree that allowing |
Beta Was this translation helpful? Give feedback.
-
At first, I thought this was equally bizarre that this happened. Foo<T>() => default(T)==default;
...
Foo<int>(); // false
Foo<int?>(); // true
Foo<string>(); // true But, then I realized in this comparison, since |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
This isn't exactly a proposal but an open discussion regarding the complications of making the following possible.
The question as to why this will not compile was asked on StackOverflow and the answer seems to be there is no IL opcode to map the
==
operator to the appropriate equality comparer at run-time. So whiledefault(T)
on it's own can be evaluated at run-time,value == default(T)
cannot.I'm no language expert. I don't even know whether the above is true. Aren't operators resolved at JIT? Are operators only resolved at compile-time? I find it hard to believe to be the case since operators can be overloaded, inherited and polymorphasised which means they have to be resolved just in time. If that's the case and if generic methods are also JITed to methods that accept concrete types at run-time, why can't the combination of the two,
value == default(T)
work? The steps I see for this to work arevalue == default(T)
default(T)
==
is not defined for that typeI guess the problem begins in the statement above when throwing is brought into the picture, I will open the debate with the argument that since only a generic default value equality comparison can throw, and not anything else, it is okay.
I do also have some concerns regarding the behaviour of the default literal surrounding generics,
If
T
is a reference type and value is null this comparison returns true. IfT
is an int, the IL code still does a null check which returns false whenvalue = 0
, the default. Isn't that incorrect by definition? This behaviour seems to be counter intuitive and confusing. Is this intended due to some circumstance that I'm not seeing?To summarise,
value == default(T)
possiblevalue == default
andvalue == default(T)
Now that I get to the end of this write up perhaps the latter bears more importance.
Credits to this discussion here
Beta Was this translation helpful? Give feedback.
All reactions