33

I received a compilation error for the following code:

if(true)
    int a = 10;
else
    int b = 20;

If I change it to the following code, then there is no compilation error:

if(true) {
    int a = 10;
}
else {
    int b = 20;
}

Why is the first syntax wrong, and from what language standard?

The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
Orup
  • 559
  • 1
  • 5
  • 14
  • Is it not? Without the braces, you're conditionally declaring a variable (which is not allowed)? With the braces, you're declaring a block scope variable? – Ruan Mendes Dec 23 '14 at 16:39
  • `/tmp/java_fCmGzo/HelloWorld.java:18: error: variable declaration not allowed here int b = 20;` – Ruan Mendes Dec 23 '14 at 16:42
  • 1
    After doing some testing, it seems JVM doesn't like having variable declarations inside an `if-else` without braces. I'm sure someone could go more in-depth with this, but my *guess* is the scope can't be resolved. `System.out.println()` works without braces. – Drew Kennedy Dec 23 '14 at 16:43
  • 3
    @DrewKennedy It wouldn't be so crazy if declaring variables inside `if-else` without braces isn't allowed. You're setting a variable which you can never use. – Daniel Dec 23 '14 at 16:46
  • 3
    @Daniel I was just thinking that too. If you're allowed only one line of code after the `if`, declaring a variable wouldn't make sense. – Drew Kennedy Dec 23 '14 at 16:48
  • @almasshaikh I don't know if this is a duplicate. The fact that the answer to that question is the same as the answer to this question doesn't necessarily mean they are the same question. – Daniel Dec 23 '14 at 16:51
  • @Daniel See OP there as well has same issue. The only difference here OP is defining int whereas There OP had Main class. So it is a duplicate and with same question. – SMA Dec 23 '14 at 16:53
  • 1
    @almasshaikh: This isn't looking like a dupe. It may be similar, but it'd make sense to keep the semantics of `if` and `for` distinct. – Makoto Dec 23 '14 at 16:58
  • @Daniel The language designers could have decreed that this is legal and declares the variable in the scope outside the `if`, so that it could be used later. But this would make the code difficult to read and invite more coding errors, so that's a good enough reason for Java to disallow it. Of course that means that JavaScript probably does allow it, although I haven't tested it ... :) – ajb Dec 23 '14 at 17:00
  • @ajb JavaScript does allow it. In fact, JavaScript would allow you to declare a variable in an `if(false)` and even use the variable _before_ that declaration! – Daniel Dec 23 '14 at 17:02
  • 1
    @Daniel, that's because JavaScript has no block scope and applies variable hoisting. http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html – Ruan Mendes Dec 23 '14 at 18:27

5 Answers5

27

The Java specification says that an if-then-else statement is of the following form:

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

Where Statement and StatementNoShortIf can be various things including blocks (code surrounded with braces), assignments (to already declared variables), other if statements etc.

Of note is that declaration statements (e.g. int a; or int a = 10;) are missing from that list, thus you get a compilation error.

For the full list, you can read the Java specification here: http://docs.oracle.com/javase/specs/

sunil
  • 556
  • 6
  • 20
  • 2
    This should be enough to answer the question, just a little bit surprise for a c++ programmer with this kind of error. – Orup Dec 23 '14 at 23:28
  • And with the answer in 'A single-line loop with a mandatory pair of braces in Java' should make it clear enough to the question. – Orup Dec 23 '14 at 23:34
  • What does `NoShortIf` refer to? – Navin Dec 24 '14 at 07:43
  • 3
    @Navin The _NoShortIf_ is to prevent situation with nested if statements where a reader of the code cannot easily decide (or might get confused) to which if an else branch belongs to. This is explained in [section 14.5 of the Java Language Specification](http://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.5) – Mark Rotteveel Dec 24 '14 at 08:34
  • @MarkRotteveel Nifty! – Navin Dec 24 '14 at 09:14
20

Lets analyze what your first code example would mean for the language design

if(condition)
    int a = 10;
else
    int b = 20;

Either it means that depending on the condition we have defined a or b. As we don't know which branch was taken, how do we use either a or b after the if-statement? We can't (and if we could that would probably result in strange bugs).

So as language designers we decide that a and b are not visible outside their respective branches to avoid these weird bugs. But as a block-less branch can only have a single statement, we have declared a (or b) only to be immediately unreachable/unusable again, so doing that makes no sense. Therefor we decide that a variable declaration is only allowed with a block. A block can have multiple statements, so variables declared in that block can be used by those other statements.

The designers of Java probably applied similar reasoning, so they decided to only allow declaration in a block. This is done through the definition of if (JLS 14.9):

IfThenStatement:
    if ( Expression ) Statement

IfThenElseStatement:
    if ( Expression ) StatementNoShortIf else Statement

IfThenElseStatementNoShortIf:
    if ( Expression ) StatementNoShortIf else StatementNoShortIf

Statement (JLS 14.5)

Statement:
    StatementWithoutTrailingSubstatement
    ...

StatementNoShortIf:
    StatementWithoutTrailingSubstatement
    ...

StatementWithoutTrailingSubstatement:
    Block
    ...

Block (JLS 14.2):

Block:
    { [BlockStatements] }

BlockStatements:
    BlockStatement {BlockStatement}

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

And LocalVariableDeclarationStatement (JLS 14.4), which repeats that it can only occur within a immediately enclosing block:

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
13

JLS-14.4. Local Variable Declaration Statements reads (in part),

Every local variable declaration statement is immediately contained by a block.

And

JLS-14.9. If Statmenets

Otherwise, execution continues by making a choice based on the resulting value:

If the value is true, then the contained Statement is executed; the if-then statement completes normally if and only if execution of the Statement completes normally.

If the value is false, no further action is taken and the if-then statement completes normally.

However, JLS-14.5. Statements doesn't include variable declaration.

Defining two different variables within the scope of a single-statement block (containing just the variable definitions) makes them both unreachable. I think you'd have better luck with a ternary expression

int a = (condition) ? 10 : 20;

or

int a;
if (condition)
    a = 10;
else
    a = 20;

or

int a;
if (condition) {
    a = 10;
} else {
    a = 20;
}

Note that the variable a is then initialized to a value based on the condition and it is reachable after that statement.

Community
  • 1
  • 1
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • 1
    I disagree with your assessment _"So your first example creates a block for int a which terminates the if block (and thus your else has no matching if)."_ The reason is the definition of statement and block in the JLS – Mark Rotteveel Dec 23 '14 at 16:53
  • 1
    @MarkRotteveel is right. The error has nothing to do with the `else`. If you take out the `else` part you still get an error. – ajb Dec 23 '14 at 16:54
  • @Mark Edited. Thanks for your input, do you think it reads better now? – Elliott Frisch Dec 23 '14 at 16:59
  • And if it were allowed, how would you reach it? Hence, I think, why it *isn't* allowed. – Elliott Frisch Dec 23 '14 at 17:04
  • You are right that reachability is probably the reason for the syntax, but the reason for the error is the actual syntax of Java as described in the JLS. – Mark Rotteveel Dec 23 '14 at 17:06
  • 1
    I removed my earlier comment, you are entirely right with your last edit; I was approaching it too much from the syntax point of view, and not from the reasons for that syntax. – Mark Rotteveel Dec 23 '14 at 17:16
  • These examples `if... int a = ... else int a = ...` doesn't match the question. The Question is `if... int a =... else int b =...` – WernerCD Dec 23 '14 at 21:17
  • @WernerCD Read the rest of the answer. Such a variable would never be reachable. – Elliott Frisch Dec 23 '14 at 21:17
6

Every local variable declaration statement is immediately contained by a block. Local variable declaration statements may be intermixed freely with other kinds of statements in the block.

Read this http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.4

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Lalith J.
  • 1,391
  • 4
  • 16
  • 27
0

My best guess is that you cannot declare variables conditionally.

  • When you don't have braces, you're trying to declare a variable conditionally in the outer scope, that's not allowed.
  • When you add the braces, you're creating the variables in that local scope (which are not allowed to be used outside of those braces)
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • 1
    I know this is probably not accurate, I'd love for someone to explain what the problem with the answer is. – Ruan Mendes Dec 23 '14 at 16:56
  • this answer is helpful to me. – Grijesh Chauhan Dec 24 '14 at 07:03
  • I think your guess is just.... you know... a guess. Other answers provide documentation and the exact 'why' of this behaviour. – Alessandro Da Rugna Dec 24 '14 at 14:59
  • @AlessandroDaRugna And your comment did not explain what the actual problem was. The answers that are here are extremely technical, I've written a layman's explanation as to why the designers of Java may have chosen to implement it this way. – Ruan Mendes Dec 24 '14 at 15:07
  • @Juan You have expressed your **opinion** instead of answering the question. You are probably right and I agree with you, but this isn't the answer the OP was looking for. – Alessandro Da Rugna Dec 24 '14 at 15:11