Objectos Weekly #010: Blocks are statements in Java

Marcio Endo
January 22, 2023

Welcome to Objectos Weekly issue #010.

You may have noticed I have been reading the Java Language Specification. I am learning a bunch of details about the language that are new to me. And I have been sharing these findings with you.

Lately, I have focused on blocks; that curly brackets thingy where you can write statements. Or not... blocks can be empty as well.

In this issue, I will tell you about the fact that blocks are statements in Java.

In the next (or a future) issue, I will talk about instance and static initializers, which are also blocks.

Let's begin.

Block is a statement

Blocks are statements in the Java programming language. If you are curious, you can look at the grammar. This means we can write the following over the top hello-world-like program:

public class Blocks {
  public static void main(String[] args) {
    {
      {
        {
          System.out.println(
            "I'm inside 4 nested blocks!");
        }
      }
    }
  }
}

When executed, it prints:

I'm inside 4 nested blocks!

Wait, did you say four blocks?

Blocks and body methods

Syntactically speaking, the body of a method is also a block.

Method declarations are defined in section 8.4 of the Java Language Specification (JLS):

MethodDeclaration:
  {MethodModifier} MethodHeader MethodBody

The MethodBody production is defined a little later in section 8.4.7:

MethodBody:
  Block
  ;

So the body of a method can be either:

That's why, in the previous section, the example prints "4 nested blocks".

Blocks and local variables

Blocks are explained in chapter 14 of the JLS. The introduction of the chapter has the following to say about blocks:

Blocks are explained first (§14.2), both because they can appear in certain places where statements are not allowed and because one kind of statement, a local variable declaration statement (§14.4.2), must be immediately contained by a block.

So it seems blocks and local variables share a special relationship. I assume this relationship has to do with the lexical scope of the latter.

Local variables with the same name

The following Java code does not compile:

public class LocalVar1 {
  public static void main(String[] args) {
    var message = "First!";
    System.out.println(message);

    // does not compile!
    var message = "Second!";
    System.out.println(message);

    // does not compile!
    var message = "Third!";
    System.out.println(message);
  }
}

It tries to define three different variables with the same name. This is not allowed. So compilation fails with the following message:

$ javac -d /tmp src/main/java/post/LocalVar1.java 
src/main/java/post/LocalVar1.java:13: error: 
  variable message is already defined in method main(String[])
    var message = "Second!";
        ^
src/main/java/post/LocalVar1.java:16: error:
  variable message is already defined in method main(String[])
    var message = "Third!";
        ^
2 errors

Let's try to fix the compilation errors.

Local variables with the same name (redux?)

On the other hand, the following compiles without errors:

public class LocalVar2 {
  public static void main(String[] args) {
    {
      var message = "First!";
      System.out.println(message);
    }
    {
      var message = "Second!";
      System.out.println(message);
    }

    var message = "Third!";
    System.out.println(message);
  }
}

We have enclosed the first and the second variables in two distinct and separate blocks. In doing so, we restricted the scope of both variables to their respective enclosing blocks.

When executed, it prints:

First!
Second!
Third!

So we could say that the enclosing block of a local variable defines what local means. In other words, a variable is local to its immediately enclosing block.

But blocks can be nested inside other blocks.

Nested block

Let's nest the second block inside the first one. Like so:

public class LocalVar3 {
  public static void main(String[] args) {
    {
      var message = "First!";
      System.out.println(message);

      {
        // does not compile!
        var message = "Second!";
        System.out.println(message);
      }
    }

    var message = "Third!";
    System.out.println(message);
  }
}

After this change our code to does not compile anymore:

$ javac -d /tmp src/main/java/post/LocalVar3.java 
src/main/java/post/LocalVar3.java:15: error: 
  variable message is already defined in method main(String[])
        var message = "Second!";
            ^
1 error

The message variable declared in the first block is visible to the second block. So, in the second block, we are not allowed to create a local variable with the same name.

Why?

So, why is block a statement? I don't know the answer.

But I assume that statements which contain other statements might be one of the reasons.

The if statement

The if-then statement is defined in Section 14.9 of the JLS:

IfThenStatement:
  if ( Expression ) Statement

Notice how it is a statement that contains another statement.

So we can combine an if statement with a return statement for example:

if (isEmpty()) return "[]";

But, since block is a statement, we can also write:

if (condition()) {
  foo();
  bar();
}

So it is quite convenient to the if statement that block is also a statement.

In other words, if block was not a statement, the if statement grammar production would need to be changed; it would require additional rules to represent the second form.

Other statements

It works the same with other statements. Let's see the while statement for example:

WhileStatement:
  while ( Expression ) Statement

It is also a statement that contains another statement.

So you can combine the while statement with the break statement:

while (true) break;

Though one could argue this is not very useful...

And, as block is a statement, you can also write:

while (keepGoing()) {
  stepA();
  stepB();
}

Of course, there are more examples of statements which contain other statements. But I think this is enough for now.

Take these with a grain of salt

As mentioned, I don't know if the statements in the previous section are the reason why block itself is a statement. It is only my assumption.

Additionally, while the syntax allows you to write code in the form:

void method() {
  {
    var foo = foo();
    bar(foo); 
  }
}

This is hardly an example of "idiomatic" Java. Granted, different teams or individuals will have different views on what is "idiomatic". But still, it might confuse readers for no good reason.

Let's work together

Do you feel that adding features to your Java applications is taking longer as time goes by? Perhaps I can help. Let's get in touch.

You can find my contacts on this page. All work will be provided via Objectos Software LTDA based in São Paulo, Brazil.

Until the next issue of Objectos Weekly

So that's it for today. I hope you enjoyed reading.

The source code of all of the examples are in this GitHub repository.

Please send me an e-mail if you have comments, questions or corrections regarding this post.