简体   繁体   中英

Can’t declare local variable inside conditional statement

This is allowed:

        // scope_1
        int i = 100;
        if (i > 50)
        {
            // scope_2
            int a = 200;
        }

This gives error:

        // scope_1
        if (100 > 50)
            int a = 200;

Is the reason second code example gives us error due to scopes? Thus compiler doesn't allow for variable a inside particular scope to be declared only if conditional statement evaluates to true, since if it did allow that, then there would be no way for compiler to figure out whether to allow the declaration of another variable named a within scope_1?

if (100 > 50)
    int a = 200;

Why would you want to do this? Declaring a variable in a one-statement scope where the statement is the variable doesn't seem to make sense, since you'd never actually have the time to use the declared variable.

The above would result in a conditional variable declaration if you were allowed to reference a outside the if statement. However, declarations cannot be conditional. What could a compiler reasonably do when it encounters an identifier that can be either declared or undeclared? Whichever is the case can only be figured out during run-time, not during compile-time; however the compiler needs to know (because undeclared identifiers are a syntax error), and therefore it will complain about this construct.

You are not using brackets in your if statement, so only one statement is allowed thereafter. What's the point of dimensioning a variable if it's impossible to be referenced?

Also, your second if statement uses literal constants, and will obviously never be true. So again, what's the point of putting anything inside it?

Maybe I misunderstood your question.

Let me rephrase your questions a bit.

What section of the spec defines this behaviour?

Section 8.7.1 states that the statement of an "if" is an "embedded statement".

The beginning of section 8 states that an embedded statement can be a block or an empty, expression, selection, iteration, jump, try, checked, unchecked, lock, using or yield statement, but not a labeled statement or a declaration statement.

Why not allow declaration statements?

The original language notes do not address this specific point, but we can make some educated guesses. Your conjecture is a good one; doing so would make it hard to reason about the scope of the declared local. If we allowed it then we'd have to decide whether the "if" implicitly creates a local variable declaration scope even without the block:

if (x) int y = M();
else string y = N();

Is this a redeclared local variable error? Or does each branch of the conditional produce its own local variable declaration space?

What about this?

if(x) int y = M();
else y = N();
Q(y);

Is y in scope outside of the consequence? If so, is it definitely assigned by the time it gets to Q(y)?

I don't have a strong intuition for what the right thing to do here is. No matter which we picked, it seems likely that half the people would think that we chose the wrong one. Far better to instead make the whole think illegal and require braces if you want to introduce a new local variable declaration space.

And now some questions you didn't ask:

What about switch blocks? Do the same rules apply?

No. Read this:

http://ericlippert.com/2009/08/13/four-switch-oddities/

What happens if I declare a local variable legally but only ever assign to it, as in my example with the block in the consequence of the conditional?

Sometimes you get a warning. Sometimes you don't.

How does the compiler decide whether to give a warning or not?

Read this:

http://blogs.msdn.com/ericlippert/archive/2007/04/23/write-only-variables-considered-harmful-or-beneficial.aspx

Look at your second case:

if (100 > 50)
    int a = 200;

The variable you're declaring, "a", would only be usable in that single statement. However, it's an l-value, so the entire purpose of defining a variable would be to use it later.

You couldn't do (for obvious reasons):

if (100 > 50)
    int a = 200;

Console.WriteLine(a); // This makes no sense... What happens if 100 < 50????

The compiler is smart enough to error out in this instance, since there's really no way you could ever use that variable if it were allowed.

because you wont be able to acces to access it out side the { }. If compiler lets you do this, the scope of variable

a

will be limited to the braces.

        // scope_1
        int i = 100;
        if (i > 50)
        {
            // scope_2
            int a = 200;
        }

        // if you will try
        int anotherA = a; // a does not exist in the current context

Have a look at

Statements

It is not mandatory for the if statement to have the {} if we want to limit its scope to only one line. However, we cannot have a variable declaration as the only line following it. This is because if the condition results to false, the variable will never be created.

Also have a look at

Statements (C# Programming Guide)

An embedded statement that is not enclosed in {} brackets cannot be a declaration statement or a labeled statement.

The second scope is created for containing only one instruction,thereby declaring a variable(which is already one instruction) would be useless,because it is usable only in that scope.

The compiler is never wrong!

This has nothing to do with compiler smarts about "scope" and whether or not a is visible outside of the if .

The C89 standard wouldn't allow either construct. In C99 you're allowed to declare a variable at the beginning of a block (a compound statement) and nowhere else.

This code doesn't have a block:

 if ( i )
   int a = 100;

It doesn't have an implied block either -- that's probably what you're thinking. The "if" can be followed by a statement or a compound statement. The compound statement is where you're allowed to have a declaration list. This thing above is just a statement.

You can turn it into a compound statement by adding {}'s.

if ( expression ) statement

Where statement can be either a single statement , or a compound-statement .

compound statement : { declaration-list statement-list }

(See also K&R 2ed A9.3 "Compound Statement")

As noted, this is a C# question. The C# standard goes on about this in section 15.2 but not as concisely. :) Basically, a declaration needs a block. A block needs braces. End of story.

The error you get is:

error CS1023: Embedded statement cannot be a declaration or labeled statement

This means that the syntax for an if-statement requires a statement or a statement-block following the conditional-expression .

if-stmt -> 'if' '(' expr ')' stmt ['else' stmt]  

stmt ->    if-stmt
     ->    do-stmt
     ->    ...etc...
     ->    '{' [declaration...] [stmt...] '}'

A declaration is not a statement , so it's a simple syntax error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM