Family said:
Tom said:
Tom Dacon wrote:
Well, this is unusual:
this doesn't compile for me on VS2008 SP1:
Int32 i = (Int32) - 1;
That's not unusual - that's clearly incorrect.
"- 1" is != "-1"
Having a space after the negative sign is wrong if you are trying to
represent a negative number.
But the following compiles and displays -1, as expected.
static void Main(string[] args)
{
int i = - 1;
Console.WriteLine(i);
Console.ReadKey();
}
Right. It's important to note here that the whitespace isn't relevant. You can write "int i = (int) - 1;" and that will still
successfully compile, and you can also write "Int32 i = (Int32)-1;" and that will still fail to compile.
Don't get distracted by the whitespace. It's not important to the question.
I agree that at first blush, this _looks_ like a compiler bug. However, IMHO the C# specification is clear about what's supposed
to happen here and why. In particular, from "7.6.6 Cast expressions":
The grammar for a cast-expression leads to certain
syntactic ambiguities. For example, the expression
(x)–y could either be interpreted as a cast-expression
(a cast of –y to type x) or as an additive-expression
combined with a parenthesized-expression (which computes
the value x – y).
To resolve cast-expression ambiguities, the following
rule exists: A sequence of one or more tokens (§2.3.3)
enclosed in parentheses is considered the start of a
cast-expression only if at least one of the following
are true:
• The sequence of tokens is correct grammar for a type,
but not for an expression.
• The sequence of tokens is correct grammar for a type,
and the token immediately following the closing parentheses
is the token “~”, the token “!”, the token “(”, an identifier
(§2.4.1), a literal (§2.4.4), or any keyword (§2.4.3) except
as and is.
The term “correct grammar” above means only that the sequence
of tokens must conform to the particular grammatical production.
It specifically does not consider the actual meaning of any
constituent identifiers. For example, if x and y are
identifiers, then x.y is correct grammar for a type, even
if x.y doesn’t actually denote a type.
From the disambiguation rule it follows that, if x and y are
identifiers, (x)y, (x)(y), and (x)(-y) are cast expressions,
but (x)-y is not, even if x identifies a type. However, if x
is a keyword that identifies a predefined type (such as int),
then all four forms are cast-expressions (because such a
keyword could not possibly be an expression by itself).
Note in particular the last two paragraphs. The first clarifies that when applying this rule, _what_ an identifier represents
isn't relevant; only the syntactical construction matters.
The second clarifies that the grammar analysis considers built-in keywords differently from identifiers. In particular, while
"int" is an alias for "System.Int32", it is _also_ a language-defined keyword, while System.Int32 is not.
Hence the different treatment: when you write "Int32", because the rule doesn't care what that identifier is but rather simply
that it is an identifier and not a reserved word, that _could_ be "correct grammar for an expression", causing neither of the two
conditions in the rule to be true. But when you write "int", since that's a reserved keyword in the language, it's impossible for
it to be correct grammar for an expression, and thus the first condition applies, allowing for the cast of the unary expression.
IMHO, the lesson here is that if one is going to try to parse C#, one needs to read the entire specification and be very careful
to apply the specification exactly as it's written. It's not sufficient to just look at the grammar as described in the
specification, and one definitely can't rely on a "common-sense" description of the grammar.
For what it's worth, .NET already provides classes for interpreting C#, for the purpose of compiling it. I don't recall if the
expression tree support includes feeding it plain C#, but there might even be a way to accomplish that, depending on your specific
goals. It might be that it makes more sense to use the built-in support in .NET, rather than trying to reinvent that particular
wheel.
Hope that helps.
Pete