RFR: 8341782: Allow lambda capture of basic for() loop variables as with enhanced for()

Archie Cobbs acobbs at openjdk.org
Thu Oct 10 15:54:13 UTC 2024


On Thu, 10 Oct 2024 11:35:45 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

> Regardless, I think I found an issue with the current implementation when there are nested loops:

Yep - thanks, very interesting. To clarify the intent, a variable is capturable if it is not **reassigned in the loop**, which is defined as:

* Wherever the variable occurs as the left hand side in an assignment expression, it is definitely unassigned
* The variable never occurs as the operand of a prefix or postfix increment or decrement operator

In your example with `i = 42`, the variable `i` is not DU at that point (even though it takes two loops around the inner loop in `AssignAnalyzer` to figure that out). So according to the original intent, it should not be capturable.

I'll work on fixing this (and add a new test case).

> I think there seem to be some more general principle here that is struggling to get out...

Agreed... I had a similar vague thought while wondering "What about `while { }` and `do { }` loops?" In other words, is there some coherent way that we could we spread this new capturable goodness more widely?

One simple idea for generalizing the current approach: Within any scope _S_, any normal variable _v_ that is visible in _S_ is capturable if it is not reassigned in _S_. I don't know if the JLS actually defines "scope" but you know the idea: a region of code in which variables can be declared and be visible; so `{ ... }` curly braces obviously, but also the body of a `for()` statement.

An example that would then be allowed:

int i, j = 0;
while (true) {
  j += i;
  {
    Runnable action = () -> foo(i + j);
    try {
        this.executor.submit(action).get();
    } catch (InterruptedException e) {
        break;
    }
  }
  i++;
}

Note the extra curly braces required to create the "well-behaved" region.

It's almost as if the "well-behaved" region "captures" the variables that it uses and makes them temporarily effectively final... which then begs the question, why not just cut out the middle man? That would then put us in a situation where any variable could be captured anywhere (which some have argued for), i.e., everything is effectively final at the point of capture.

So I'm not sure if a coherent middle ground exists or what it would be.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/21415#discussion_r1795713812


More information about the compiler-dev mailing list