Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8300691

final variables in for loop headers should accept updates

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • None
    • specification
    • None

      (N.B. This is a small language change, and so if we address it, it actually needs its own JEP, or else to be rolled into a Coin-like JEP.)

      Problem: Classic Java for-loops (not enhanced for-loops) declare index variables which are mutated in the for-loop header, in the second clause (test) or third clause (step), or both. This conflicts with lambda capture and other legitimate uses of final declaration. Since the index variable is not final it cannot be captured.

      ```
      for (int i = 0; i < a.length; i++) {
        process(a[i]); //OK
        process(() -> a[i]); //NOT OK
      }
      ```

      This is a sharp edge frequently encountered by programmers. The workaround is to copy the declaration into the loop body:

      ```
      for (int i$orig = 0; i$orig < a.length; i$orig++) {
        int i = i$orig;
        process(a[i]); //OK
        process(() -> a[i]); //OK
      }
      ```

      This workaround makes the code harder to read and reason about, a significant problem for Java.

      Solution: Automate the workaround.

      If a for-loop declares a final variable, it has a special permission to update that final variable in its header. If a for-loop header contains such an update, then the variable is renamed in the for-loop (to an invisible name, as `i$orig` above) of a synthetic variable. The synthetic variable is non-final. The declaration is copied to the top of the for-loop body, with the initializer is changed to the invisible name.

      If there is more than one such variable, they are all given this treatment.

      Annotations on the type and the declaration are duplicated, as with record class components.

      We confirm that all the "implicitly final" rules apply to variables declared in for-loops, and that if such a variable is deemed implicitly final, then the above rules kick in. This is what allows lambdas to capture for-loops without special efforts from the user.

      Benefit: Lambda capture of for-indexes, a frequent use case.

      Benefit: As a style choice, routinely declaring a for-loop variable as final will make the code easier to read and reason about, for the exactly same reasons declaring parameters or other locals as final is (for some) a good stylistic choice. Looking at it from one angle: Forbidding final on 10% of your locals is a language smell.

            Unassigned Unassigned
            jrose John Rose
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: