[External] : Re: This expression in lambda in early construction context

Gavin Bierman gavin.bierman at oracle.com
Wed Jun 12 09:05:55 UTC 2024


Thanks Ella. Does look like we need to strengthen the spec. Archie’s change clearly works for this example, but I am a little worried that it’s fragile. I will need to check it. Not sure we are going to make the 23 train with this though…will let you know when I have something.

Thanks,
Gavin

On 7 Jun 2024, at 23:10, Archie Cobbs <archie.cobbs at gmail.com> wrote:

I think Ella may have a valid point from the point of view of the specification - i.e., where in the new spec does it specify that the new LHS field assignment exception doesn't apply within a lambda?

§6.5.6.1 says:

If the expression name appears in an early construction context of C (8.8.7.1), then it is the left-hand operand of a simple assignment expression (15.26), and the declaration of the named variable lacks an initializer.

But the definition of early construction context includes all contained lambdas, subclasses, etc.

So maybe it should instead say something like:

If the expression name appears in an early construction context of C (8.8.7.1), then it is the left-hand operand of a simple assignment expression (15.26), the declaration of the named variable lacks an initializer, and the expression is not contained in any lambda or class declaration that is contained in C.

-Archie

On Fri, Jun 7, 2024 at 4:35 PM Maurizio Cimadamore <maurizio.cimadamore at oracle.com<mailto:maurizio.cimadamore at oracle.com>> wrote:

Hi Ella,
the problem here is that, since the lambda needs to refer to "this", it's as if you need to pass "this" to create the lambda object.

To make it simpler, you can think of the lambda as a local class (not entirely accurate, but I think it paints a good analogy for what's going on here):

class Main {
    int a;
    Main() {
        this.a = 1; //line A
        class Foo {
              Main this$0;
              Foo(Main this$0) { this.this$0 = this$0; }
              void run() { this$0.a = 1; }
        }
        Foo lmb = new Foo(this); // line A

        lmb.run(); //line B
        super();
    }


Like before, in line (A) we create the lambda expression (here modelled as a local class). Note that the local class wants a construction parameter, of type Main (since the local class needs to refer to it). But then, in line (B), we need to supply an argument of type Main, namely "this". So here we are effectively reading/accessing "this" before the super constructor has been called.

The lambda expression, being so compact, hides a bit of the problem and you are right that it's a bit confusing at first, but I hope the example above clarifies things a bit.

Cheers
Maurizio

On 05/06/2024 22:29, Ella Ananeva wrote:
Thanks for pointing this out, Chen.
Please bear with me for a moment. If we have a lambda as a local variable in the constructor, it cannot be invoked outside of the constructor, right?

class Main {
    int a;
    Main() {
        this.a = 1; //line A
        Foo lmb = () -> this.a = 1;
        lmb.foo(); //line B
        super();
    }


--
Archie L. Cobbs

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240612/67f8f49c/attachment-0001.htm>


More information about the amber-dev mailing list