silph silph - 1 month ago 7
Java Question

What does the JLS mean by statements do not have values?

I was surprised that the following line:

3;


gives a compiler error in java: "Not a statement".

I looked at the Java Language Specification. Chapter 14 starts with the following:


Chapter 14: Blocks and Statements

The sequence of execution of a
program is controlled by statements, which are executed for their
effect and do not have values.


(https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html)

But this confuses me. The following line of code is one that the java compiler does not complain about:

Math.pow(2, 3);


so I presume that it is a statement. But it certainly does have a value, doesn't it?

What does the JLS mean by statements do not have a value, in consideration that

Math.pow(2, 3);


does seem to me to have a value?

Answer

A method call (returning non-void type) is an exception. It is both a statement and an expression.

The relevant productions are:

Statement ::= ... |
    ExpressionStatement

ExpressionStatement ::= StatementExpression

StatementExpression ::= 
    Assignment |
    PreIncrementExpression |
    PreDecrementExpression |
    PostIncrementExpression |
    PostDecrementExpression |
    MethodInvocation |
    ClassInstanceCreationExpression |

Source: JLS 14.5, JLS 14.8.

Note that other expressions can be used as statements too ... but not all of them. The distinguishing feature is whether the expression or part of it is patently side-effect-free. For example:

  i + j     // no possibility of side effects
  i++       // side effects
  foo()     // possible side effects
  foo() + 1 // no possibility of side effects in the `... + 1` part.

The JLS does not actually attempt to figure out / distinguish methods that are side-effect free. In your example, Math.pow is side-effect free, but that is not taken into consideration. (And indeed, the compiler probably could not work that out, because pow is implemented in native code.)


The JLS text that you quoted:

The sequence of execution of a program is controlled by statements, which are executed for their effect and do not have values.

should be interpreted as saying that statements do no >>produce<< values that can be captured and used for anything.

  • The case of the ExpressionStatement ::= StatementExpression can be viewed as an implicit throwing away of the value (if any) produced by the expression. The effect (or potential effect) happens before that.

  • In the case of other expressions, like i + j or 3 there is no "effect".


Does this matter?

Not really. The only case I can think of where you might want to use a simple expression for its effects is something like this:

  sideEffectFunction1() || sideEffectFunction2();  

but you can write that as:

 if (!sideEffectFunction1()) { sideEffectFunction2(); }