Variable declarations following if statements
An issue came up on another forum and I knew how to fix it, but it revealed a feature of the compiler peculiar to me. The person was getting the error "Embedded statement cannot be a declaration or labeled statement" because they had a declaration of a variable following an if statement with no brackets. That was not their intent, but they had commented out the line of code immediately following the if statement, which made the variable declaration the de facto line of code to execute. Anyway, that's the background, which brings me to this.
The following code is illegal
if (true)
int i = 7;
However, if you wrap that in brackets, it's all legal.
if (true)
{
int i = 7;
}
Neither piece of code is useful. Yet the second one is OK. What specifically is the explanation for this behavior?
The C# language specification distinguishes between three types of statements (see chapter 8 for more details). In general you can have these statements:
-
labeled-statement - my guess that this is for the old-fashioned
goto
statement - declaration-statement - which would be a variable declaration
- embedded-statement - which includes pretty much all the remaining statements
In the if
statement the body has to be embedded-statement, which explains why the first version of the code doesn't work. Here is the syntax of if
from the specification (section 8.7.1):
if ( boolean-expression ) embedded-statement
if ( boolean-expression ) embedded-statement else embedded-statement
A variable declaration is declaration-statement, so it cannot appear in the body. If you enclose the declaration in brackets, you'll get a statement block, which is an embedded-statement (and so it can appear in that position).
When you don't include the brackets, it executes the next line as if it were surrounded by brackets. Since it doesn't make much sense to declare a variable in that line (you wouldn't be able to use it ever), the C# compiler will not allow this to prevent you from accidentally doing it without knowing (which might introduce subtle bugs).
Here's part of Eric Lippert has to say about the C# compiler on this SO answer about name resolution:
...C# is not a "guess what the user meant" language...the compiler by design complains loudly if the best match is something that doesn't work
All compilers will allow you to compile code that is useless or of exceedingly low use. There are simply too many ways that a developer can use the language to create constructs with no use. Having the compiler catch all of them is simply too much effort and typically not worth it.
The second case is called out directly in the C# language specification at the start of section 8.0
The example results in a compile-time error because an if statement requires an embedded-statement rather than a statement for its if branch. If this code were permitted, then the variable i would be declared, but it could never be used. Note, however, that by placing i’s declaration in a block, the example is valid.
Example Code
void F(bool b) {
if (b)
int i = 44;
}