C# Language Design: method group inside `is` operator
Asked Answered
H

2

28

I'm interesting in some design choices of C# language. There is a rule in C# spec that allows to use method groups as the expressions of is operator:

class Foo {
  static void Main() { if (Main is Foo) Main(); }
}

Condition above is always false, as the specification says:

7.10.10 The is operator

If E is a method group or the null literal, of if the type of E is a reference type or a nullable type and the value of E is null, the result is false.

My questions: what is the purpose/point/reason of allowing to use the C# language element with no runtime representation in CLR like method groups inside the such "runtime" operator like is?

Honduras answered 12/7, 2010 at 20:7 Comment(5)
That's... stunning. The section on the as operator makes no mention of method groups.Weekley
@Tim: But the "as" operator is defined as a syntactic sugar for a combination of casts, the conditional operator and the "is" operator, so the "as" operator doesn't need to mention method groups.Tomb
So Main as Foo is always null. And Main as System.Action is also null, whereas System.Action a = Main is fine.Weekley
By the way, CS0837 The first operand of an 'is' or 'as' operator may not be a lambda expression or anonymous methodExplain
@TimRobinson (C# 5 compiler) Main as Action gives error CS0039: Cannot convert type 'method group' to 'System.Action' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion, so no, it is not null.Borer
T
21

what is the purpose/point/reason of allowing to use the C# language element with no runtime representation in CLR like method groups inside the such "runtime" operator like is?

The language design notes archive make no mention of why this decision was made, so any guess at an answer will be a conjecture. They do mention that if the result of the "is" can be statically determined to always be true or false, that it be so determined and produce a warning. It seems plausible that this could simply be an error.

The most common reason for turning what could rightly be an error into a warning (or simply allowing it) is because that lessens the burden upon producers of programs that automatically generate code. However, I don't see a really compelling scenario here.

UPDATE:

I just checked the C# 1.0 specification. It does not have this language in it. It does not say anything about nulls or method group arguments. And of course it says nothing about method group conversions because in C# 1.0 there were no implicit method group conversions; you had to explicitly call "new D(M)" if you wanted to convert method M to delegate type D.

This latter point is justification for "M is D" returning false rather than true; You couldn't legally say "D d = M;" so why should "M is D" be true?

Of course in C# 2.0 this makes less sense, since you can say "D d = M;" in C# 2.0.

I also just asked one of the people present when the "is" operator was designed and he had no memory of ever deciding this question one way or the other. His suspicion was that the original design of the "is" operator was to not give any errors, only warnings, and that all the text in the spec about what to do with method groups and nulls and whatnot was added post-hoc, for the C# 2.0 version of the spec, and based on what the compiler actually did.

In short, it looks like this was a design hole in C# 1.0 that was papered over when the spec was updated for C# 2.0. It does not look like this specific behaviour was desired and deliberately implemented.

This theory is reinforced by the fact that anonymous methods do produce an error when used as an argument to "is" in C# 2.0. It would not be a breaking change to do so, but it would be a breaking change to make "M is D" suddenly start returning true or being an error.

FURTHER UPDATE:

While investigating this I learned something interesting. (To me.) When the feature was originally designed, the design was to allow either the name of a type, or a Type object as the right-hand argument to "is". That idea was abandoned well before C# 1.0 shipped though.

Tomb answered 12/7, 2010 at 20:34 Comment(0)
G
3

First of all a method is not a type, msdn clearly states the following:

The is operator is used to check whether the run-time type of an object is compatible with a given type

Example

public static void Test (object o) 
{
   Class1 a;

   if (o is Class1) {}
}

From MSDN:

An is expression evaluates to true if both of the following conditions are met:

  • expression is not null.
  • expression can be cast to type. That is, a cast expression of the form (type)(expression) will complete without throwing an exception. For more information, see 7.6.6 Cast expressions.

So the reason for your example being false lands on the second point, it has to be castable to a specific type.

I hope I did not missunderstand the question.

Groundless answered 12/7, 2010 at 20:27 Comment(14)
The question is, why isn't Main is Class1 a compiler error?Explain
@SLacks: Maybe we should use Reflector to further investigate this.Gissing
@SLaks, using ReShaper I get a warning with this message: "The given expression is never provided a type". Checking with Reflector now..Groundless
@Filip: Agree. I get the warning at command line, cf: msdn.microsoft.com/en-us/library/230kb9yt%28VS.90%29.aspxGissing
@Andreas, right. It takes a "reference type", a method can be a delegate, so therefore this doesn't give you a compile time error. That's my guess anyways.Groundless
@Filip: Wrong. Method groups are untyped.Explain
Right. Does this answer add any value to the Question?Groundless
@SLaks, Yeah thats because methods are not types. :)Groundless
@Filip: Wrong. Method groups, anonymous delegates, and lambda expressions are untyped expressions, meaning that they represent a value that has no intrinsic type. (Unless you use it in delegate context, in which case it becomes the type of the delegate) This is why var a = 1 is valid, whereas var a = Console.WriteLine is invalid.Explain
@SLaks, that's what I just said, Methods are not types.Groundless
@Filip: Normal expressions are also not types, but "abc" is a typed expression, of type String.Explain
@SLaks, I don't understand where you are getting at?Groundless
A method is not a type, but any other expression is also not a type. I think you meant to say, "a method doesn't have a type".Explain
@SLaks, I might be lost in translation here. :)Groundless

© 2022 - 2024 — McMap. All rights reserved.