1

Using Scala 2.10, the following compiles without an error.

val test = 1
try {
  val test = 2
}

Looking at the byte code generated, I see this:

int test = 1;
int test = 2;

Isn't this strange? Or am I missing something obvious?

zakvdm
  • 479
  • 2
  • 4
  • 14
  • It's called shadowing and can happen in any setting where new inner scopes are created by virtue of enclosing a sequence of expressions in `{` braces `}`. – Randall Schulz Feb 20 '13 at 14:46
  • I know it's not actually true, but with Scala I pretend `{` and `}` define a function. That makes these kinds of structures easier to understand for me personally. – EECOLOR Feb 20 '13 at 21:55

3 Answers3

3

A local variable can always have the same name as one with wider scope. By declaring it inside your braces you effectively protect yourself from accidentally using/overwriting a variable used elsewhere . Not strange - but useful!

Floris
  • 45,857
  • 6
  • 70
  • 122
  • Thanks for the answer. A few things still puzzle me though... As far as I can tell, this behaviour is different from Java (where the same code won't compile). Why this inconsistency? Is it a natural consequence of Scala's having closures? And then there's the weird bytecode that's generated... How does this bytecode equate to an instance of "test" for the inner, and one for the outer scope? – zakvdm Feb 20 '13 at 13:58
  • I agree that the bytecode is confusing because it doesn't show the scope of the variable called "test" - thus looking at the bytecode you can't tell if they are the same variable. Does it show that they have different addresses though? Does the example of @korefn show `1 2 1` as predicted? – Floris Feb 20 '13 at 15:07
2

Perhaps you try this to get a clear picture of whats going on

val test = 1
println(test)
try{
  val test = 2
  println(test)
}
println(test)

The scope matters. I expect you got 1 2 1 The second test only exists within the try scope

korefn
  • 955
  • 6
  • 17
2

This has nothing to do with try. Variables can shadow each other in any block, and you can put blocks basically anywhere:

val x = 0
if ({val x = 1; x*3}==0) {
  val x = 2; x + x + x
}
else x

This makes code more portable: you can freely move blocks around without worrying that something on the outside might conflict. (Well, not entirely true: which implicits are in scope can still cause problems, but that's much less likely to trip you up than duplicated variables.)

It is a different choice from Java; Java's attitude is that you're more likely to forget your variable names and need to be reminded, while Scala's is that you probably mean what you say even if the outside context changes. This sort of makes sense given Java's focus on mutable operations (shadowing a mutable variable can really cause problems!) and Scala's on immutable-by-default (shadowing the outer immutable variable is probably even desirable since you can reuse short variables like i and x to your heart's content).

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • Thanks! I'm going to accept your answer because the thing that was really puzzling me is the difference between scala and java here, and I think you've provided a plausible explanation. I encountered this when creating a mutable variable and then accidentally shadowing it instead of assigning to it inside my try block. I guess I should look at some of the more idiomatic scala patterns for dealing with exceptions, :P – zakvdm Feb 21 '13 at 10:01