Effectively final effective?

Reinier Zwitserloot reinier at zwitserloot.com
Thu Feb 25 08:57:45 PST 2010


On Thu, Feb 25, 2010 at 12:37 AM, Artur Biesiadowski <abies at adres.pl> wrote:

> What about yet another solution ?
>
> ------------------
> int x = 1;
>
> Runnable x = new Runnable() {public void run() {
>   use(x); // you can use x as capture at moment of creation here
>   //x++; // illegal, x is not allowed be modified from anonymous/lamba
> scopes
> }};
>
> x = 2; // you CAN mutate it further in outside scope
>
> x.run(); // use(1) will be called inside, mutation of x is not visible
> in already captured environment
>


Doing something which causes the compiler (which in practice almost always
means: Your editor, right then and there as you make the mistake) to emit a
clear and direct error/warning message is so vastly superior to a situation
where something occurs which a programmer may not realize, and is invisible
until runtime, but there's no warning or error, it's incomparable. That last
situation is always bad and always leads to many hours of bug hunting. A
single error of that kind is obviously worse than 1000 errors where your
editor/compiler instantly points out what went wrong and points at the exact
position where you need to apply a trivial fix.

And yet that's what you are proposing: To avoid a simple, obvious, and
direct error message ("this variable is implicitly final because it is
accessed from a closure; if you'd like to mutate it, use AtomicReference"),
you've set up a situation where you implicitly create a copy of a variable,
and changing the one does not reflect into the other. Horrible, _horrible_
idea.

There's no problem with implicit final. The argument that an explicit
'final' makes things for readable doesn't really fly; you can use the same
reasoning to say that imports should go away (as well as the implicit import
java.lang.*) because "java.lang.String" is less ambiguous and less magical
than "String". Which I presume everyone realizes would be a pretty bad idea.
*Every* single character of code in a source file is both noise and signal.
You do the math on how much noise vs. how much signal there is to consider
whether making it explicit is a good idea. This clearly doesn't cut the
mustard; it's going to be 100% noise in many cases, and a rather weak signal
in the remaining few.

The situation is really very simple, either:

1. The implicit finalness is irrelevant, because nobody is mutating the
variable. Knowing that a certain variable is final when it never gets
modified in the first place in a scope that is self-contained (i.e. a local
variable that is never modified) is utterly moot.

2. The implicit finalness is relevant (in that someone is looking at code
with the intention of adding a new line of code that mutates an implicit
final), but the error in thinking of that programmer is pointed out
_immediately_, and the error message explains exactly what happened. He can
fix it in 5 seconds, and IDEs will most likely offer an instant 'hoist into
AtomicX construct' as well.

Said differently, instead of having a publically visible 'final' cluttering
up your source file, you get a "Just In Time" completely automatic final
keyword: The moment you actually attempt to write a line that mutates an
implicit final, the 'final' keyword "appears" just in time (it actually
takes the form of an immediate IDE error, but this is in many ways even
better: It's pointing right at where you are typing! - the actual variable
declaration may not even be on your screen).


More information about the lambda-dev mailing list