Minor irritations

I just noticed the following issue in Java. It’s never bothered me before, so it’s clearly not that big a deal, but I find it vaguely annoying.

The following code is not legal:

final Foo foo;
try{
  foo = stuff();
} catch (Exception e){
  foo = otherStuff(); 
}

The compiler thinks that foo might already have been assigned in the catch block, even though it clearly can’t have been.

The reason is presumably that it doesn’t distinguish it from the following code:

final Foo foo;
try{
  foo = stuff();
  bar();
} catch (Exception e){  // Might have been thrown from bar.
  foo = otherStuff(); 
}

Which is reasonable. I’m not sure if I’d really want this edge case to be handled specially.

As Ricky Clarkson pointed out in ##java, what would really be much nicer is:

final Foo foo = try { stuff(); } catch(Exception e) { otherStuff(); }

i.e. Compound expressions ala Scala (or GCC extensions, or any number of other languages). It would avoid a lot of annoying edge cases with assigning to final variables.

This isn’t really a “Please add this to Java 7” request. I don’t care enough and the list of desired features is getting annoying. It’s just a minor irritation with the language.

This entry was posted in programming and tagged , , on by .

9 thoughts on “Minor irritations

  1. Neal Gafter

    Actually, the code is illegal because an exception *can* be thrown after the assignment in the try block. Exceptions can occur at any point in a program.

  2. David R. MacIver

    I think you might have missed the point. I know why the second code example is illegal and said as much – The second code example really does have to be illegal.

    But the first example is entirely safe and can’t result in foo being assigned multiple times. The assignment is the last line in the try block, so either stuff() throws an exception and foo doesn’t get assigned or stuff() returns succesfully and so the catch block is never executed to assign to foo again.

  3. David R. MacIver

    ok. On a reread I didn’t really explain why the second code example was illegal, just that it was. That could have been clearer.

  4. Neal Gafter

    No, David, the first example isn’t perfectly safe. It doesn’t matter what *lines* the code appears on. An exception can occur at any bytecode boundary, and the assignment instruction is not required by any specification to be the last bytecode in the try block.

  5. David R. MacIver

    Oh, hm. I see what you mean. That’s interesting.

    I’m slightly struggling to think of circumstances in which this could occur, but I see why it’s a problem.

  6. Neal Gafter

    I’ll suggest two ways it could happen: Thread.stop(Exception), which has been deprecated but not removed from the platform, and a VM exception.

  7. David R. MacIver

    Ok. Fair point. I withdraw the “perfectly safe” conclusion entirely. :-)

    Compound expressions are a nicer solution to the problem anyway.

  8. Andreas Krey

    @Neal: The argumentation on the byte code level strikes me a bit odd; after all, there is no user-visible there, and no automatically inserted code.

    For all practical purposes, it does not matter whether an asynchronous exception happens before or after the assignment to foo. The catch clause will override it anyway.

    I think the real point the compiler should be looking for is whether foo is used either in the try clause after it has been set (or before, actually) or in the catch clause.

    If it allows foo to be set after its declaration at all, it may as well consider this condition.

    Before the invention of this special form for try-ing the initialization of a final variable it wasn’t even possible to reference the target variable — oops, it should have been, but the compiler says different.

    A try expression would have been a clean solution…

  9. Robert Varga

    If you put the try-catch block in a function returning the value after handling the exception, and assigning the return value of the function to the final attribute, you get exactly what you want.

    Of course, it is a bit verbose, but the Hotspot compiler will optimize away the performance disadvantages of the function call.

Comments are closed.