views:

615

answers:

5

The following method does not work because the inner block declares a variable of the same name as one in the outer block. Apparently variables belong to the method or class in which they are declared, not to the block in which they are declared, so I therefore can't write a short little temporary block for debugging that happens to push a variable in the outer scope off into shadow just for a moment:

void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
}

Almost every block-scoped language I've ever used supported this, including trivial little languages that I wrote interpreters and compilers for in school. Perl can do this, as can Scheme, and even C. Even PL/SQL supports this!

What's the rationale for this design decision for Java?

Edit: as somebody pointed out, Java does have block-scoping. What's the name for the concept I'm asking about? I wish I could remember more from those language-design classes. :)

+9  A: 

It leads to bugs that are hard to spot, I guess. It's similar in C#.

Pascal does not support this, since you have to declare variables above the function body.

OregonGhost
+6  A: 

I believe the rationale is that most of the time, that isn't intentional, it is a programming or logic flaw.

in an example as trivial as yours, its obvious, but in a large block of code, accidentally redeclaring a variable may not be obvious.

ETA: it might also be related to exception handling in java. i thought part of this question was discussed in a question related to why variables declared in a try section were not available in the catch/finally scopes.

John Gardner
I first saw this in Exception-handling. There I didn't think anything of it; I just assumed the implementation precluded it for some internal reason. It wasn't until I noticed that it affected plain blocks that I really started wondering "why"?
skiphoppy
+14  A: 

Because it's not uncommon for writers to do this intentionally and then totally screw it up by forgetting that there are now two variables with the same name. They change the inner variable name, but leave code that uses the variable, which now unintentially uses the previously-shadowed variable. This results in a program that still compiles, but executes buggily.

Similarly, it's not uncommon to accidentally shadow variables and change the program's behavior. Unknowingly shadowing an existing variable can change the program as easily as unshadowing a variable as I mentioned above.

There's so little benefit to allowing this shadowing that they ruled it out as too dangerous. Seriously, just call your new variable something else and the problem goes away.

Derek Park
I would go farther to say that there's NO reason to do this whatsoever. There's nothing you can do with shadow variables that you can't do without them.
JavadocMD
The one time I like them is in constructor arguments, so I can do "this.foo = foo". Name mangling for the sake of constructors is ugly, ugly, ugly. "_foo", "foo_", blah.
Derek Park
+6  A: 

Well, strictly speaking, Java does have block-scoped variable declarations; so this is an error:

void methodName() {
  for (int j = 0; j < 10; j++) {
    int i = j * 2;
  }
  System.out.println(i); // error
}

Because 'i' doesn't exist outside the for block.

The problem is that Java doesn't allow you to create a variable with the same name of another variable that was declared in an outer block of the same method. As other people have said, supposedly this was done to prevent bugs that are hard to identify.

Ricardo Massaro
A: 

The underlying assumption in this question is wrong.

Java does have block-level scope. But it also has a hierarchy of scope, which is why you can reference i within the for loop, but not j outside of the for loop.

public void methodName() {
  int i = 7;
  for (int j = 0; j < 10; j++) {
    i = j * 2;
  }

  //this would cause a compilation error!
  j++;
}

I can't for the life of me figure out why you would want scoping to behave any other way. It'd be impossible to determine which i you were referring to inside the for loop, and I'd bet chances are 99.999% of the time you want to refer to the i inside the method.

matt b
I do want to refer to the i inside of the method. That's how C, Perl, and Scheme all work. So why does that make it impossible to determine which i I want?
skiphoppy