allow lambdas to capture early-context this, with possible translation strategy

XMLWordPrintable

    • Type: Enhancement
    • Resolution: Unresolved
    • Priority: P4
    • None
    • Affects Version/s: None
    • Component/s: tools
    • None

      We can consider allowing lambdas to capture `this` in early construction contexts before the `super` constructor is called.

      This RFE describes a possible translation strategy. It does not attempt to justify or motivate the required change to the JLS, a serious task that may or may not be possible.

      They would be desugared differently from regular lambdas. There would be two steps in creating such a lambda, the indy which creates the object (called before `super`) and the binding of the tardy `this` (called after `super`).

      (Note that it is possible to capture other values too, not from the constructor, but from up-level scopes. So the indy might possibly take additional arguments apart from the problematic `this` argument.)

       - As always, there is an indy instruction which serves as the static factory for the lambda, an instance of a HC (hidden/anonymous class).
       - The HC would have a field for the captured `this`, as before.
       - But, the HC would declare it `@Stable`, not `final`.
       - And, the HC constructor would not mention the captured `this`.
       - The HC would have an additional private handshake for accepting a tardy `this`.
       - The indy instruction that creates the HC instance would not need to touch `this`.
       - But, the lambda would be incomplete until the `super` call.
       - Calling the lambda before that point would throw some exception.
       - Just after the `super` call javac would inject the handshake the supplies the tardy `this`. Then the lambda is ready to roll, as good as any other lambda.
       - The handshake can be supplied by a static meta-factory, called by a condy.
       - The condy supplies a MH or VH or BiConsumer (ad lib) which accepts the lambda, and the tardy `this`, and smashes them together.

      Details of BSM wiring could vary. The condy BSM could refer to the same BSM arguments as the indy. (This might be problematic, since the HC should not be spun twice.) Or (better) the metafactory API for this desugaring could produce a record of both the lambda factory MH and the “smasher-together” MH/VH/BiC. That record is bound to a condy, and is then used in two places, the indy which makes the lambda, and the tardy `this` binding point immediately after the `super` call.

      (Those familiar with functional language implementation might recognize that this is a special kind of letrec, and the stable captured this field is the hidden mutable state required to implement such a thing.)

      Doing this feature, however desirable, would change the JLS (an expensive tasks), and introduce a sharp edge into it. Specifically, the JLS would have to document, not only that lambdas can be created in pre-construction contexts, but also that they must NOT be invoked before the `super` call happens. (This implies a dynamic check inside the lambda body, of the captured `this` field. That’s cheap; the VM does a null check there anyway.) The JLS must document what exception will be thrown (at least, approximately); perhaps it is an IllegalStateException. Users will rightly be disgusted by that possibility.

      On the other hand, there is quite already a sharp edge, arguably, in the current treatment of lambdas, that does not allow `this` to be captured in some contexts where it obviously makes some kind of sense. We can explain as follows "You can’t touch ‘this’ here, and you already know it; you can’t use ‘this’ even if it is implicit; lambdas are subject to that general rule." But it still can feel like over-restriction, if the user expected to call the lambda only "at a good time". I fully admit that adopting this RFE will only somewhat diminish the sharp edge of inaccessible `this`, creating a new sharp edge with lambdas which can suddenly throw exceptions when used.

      I do NOT propose attempting some static analysis which proves somehow that the lambda cannot be executed at the wrong time. I think that is a research problem beyond the bounds of the JLS.

            Assignee:
            Unassigned
            Reporter:
            John Rose
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: