Mittwoch, 8. Juli 2015

For Loop Scoping is Evil

Try the following in Java 7:

import java.util.List;
import java.util.ArrayList;

public class Test {
    private final List<Object> a = new ArrayList<>();

    public void doSomething()
    {
        for (Object a: a) {
        }
    }
}

As you probably expected, this does not compile, because you cannot iterate over an Object (and Object a should shadow the private field):

  error: for-each not applicable to expression type
        for (Object a: a) {
                       ^
  required: array or java.lang.Iterable
  found:    Object
However, if you consult the JLS, this behaviour is actually wrong:

The enhanced for statement is equivalent to a basic for statement of the form:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
    VariableModifiersopt TargetType Identifier =
        (TargetType) #i.next();
    Statement
}
That is, according to the specification, Object a is meant to be declared inside the for loop's block after the outer a (Expression) has already been evaluated.

Java 8 corrects this mismatch between specification and implementation and the code above compiles fine.

The effects however, are probably counter-intuitive. The enhanced for loop switches around the declaration of the variable as it appears in the code (Object a) and the point in the program where the declaration takes effect.