Minor wording issue around effectively final definition

Dan Smith daniel.smith at oracle.com
Tue Feb 12 14:41:09 PST 2013


Thanks for the feedback, Neal.

Note that the constraint about DA/DU is about the point of assignment, not the point of capture.

Here, the only assignment to 'i' occurs when it is (!DA)&&DU; and at the only use of 'i', it is DA:

int i;
i = 2;
if (false) {
    Runnable r = () -> { int j = i; };
}

So everything's okay.

The (!DA)&&DU restriction was introduced to handle situations like this:

int i;
i = 2;
if (false) {
  i = 3;
  Runnable r = () -> { int j = i; };
}

Here, 'i' is DU wherever it is assigned to; but if we were to declare 'i' 'final', there would be an error at the point of the second assignment, per JLS 7 6.5.6.1, precisely because it is also DA.  That's bad, because we want "effectively final" to mean "could have been declared final".

(The treatment of final variables in situations like this was unclear previously, so this is a spec change (bug #4721499).  I don't think it has made its way into the javac code yet.  Ultimately, the goal will be to make the spec for "final", the spec for "effectively final", and the implementation all be in sync.)

Now, back to your original example:

if (false) {
    int i;
    i = 2; // i is both definitely assigned and definitely unassigned here
    Runnable r = () -> { int j = i; }; // error: i not effectively final
}

Here, again, 'i' is both DA&&DU at the assignment, so if it were to be declared 'final', there would be an error -- you can't assign to a DA final variable.  So 'i' shouldn't be effectively final.

But maybe that just pushes the criticism back to the rules about final variables.  It is somewhat surprising that this would be illegal:

if (false) {
  int i;
  i = 2; // i is DA, represents a "value", can't be assigned to (per 6.5.6.1)
}

I'll investigate that further.

—Dan

On Feb 12, 2013, at 9:46 AM, Neal Gafter <neal at gafter.com> wrote:

> Sorry, the example should have been
> 
> int i;
> i = 2;
> if (false) {
>     // i is both definitely assigned and definitely unassigned here
>     Runnable r = () => { int j = i; }; // error: i not effectively final
> }
> 
> Cheers,
> Neal
> 
> On Mon, Feb 11, 2013 at 4:36 PM, Neal Gafter <neal at gafter.com> wrote:
> Here is one example that does not work right according to the spec:
> 
> if (false) {
>     int i;
>     i = 2; // i is both definitely assigned and definitely unassigned here
>     Runnable r = () => { int j = i; }; // error: i not effectively final
> }
> 
> One way to fix this section of the spec is to remove the words "and not definitely assigned" twice where they appear in the definition of effectively final.
> 
> On Mon, Feb 11, 2013 at 10:53 AM, Dan Smith <daniel.smith at oracle.com> wrote:
> On Feb 11, 2013, at 7:00 AM, Srikanth S Adayapalam <srikanth_sankaran at in.ibm.com> wrote:
> 
> > Hello !
> >
> >  0.6.1 (4.12.4) reads:
> >
> > A local variable or a method, constructor, lambda, or exception parameter is effectively final if it is not final but it never occurs as the left hand operand of an assignment operator (15.26) or as the operand of an increment or decrement operator (15.14, 15.15). [jsr335-4.12.4-10]
> 
> > In addition, a local variable whose declaration lacks an initializer is effectively final if all of the following are true: [jsr335-4.12.4-20]
> >
> >       • It is not final. [jsr335-4.12.4-20-A]
> >       • Whenever it occurs as the left-hand operand of an assignment operator, it is definitely unassigned and not definitely assigned before the assignment (that is, it is definitely unassigned and not definitely assigned after the right-hand operand of the assignment) (16).
> >
> > I think the first sentence meant to say, never occurs as the left hand operand of a *compound* assignment operator.
> 
> The intent is to cover both compound and simple assignments.
> 
> The first sentence says that if you never assign to a variable, it's effectively final.
> 
> The second sentence says that if you _do_ assign to a variable, it may still be effectively final if the assignment is the _first_ assignment.
> 
> Note that there's a restriction, separate from "effectively final," that a variable must be definitely assigned wherever it is referenced, including in a compound assignment.
> 
> I think the complexities you're worried about are bundled up inside the definitions of "definitely unassigned" and "definitely assigned".  But if you're unsure, feel free to share a concrete example of something you don't think will work right.
> 
> —Dan
> 
> 



More information about the lambda-spec-observers mailing list