<div dir="ltr"><div dir="ltr">On Tue, Jun 11, 2024 at 3:53 AM Maurizio Cimadamore <<a href="mailto:maurizio.cimadamore@oracle.com">maurizio.cimadamore@oracle.com</a>> wrote:</div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>

  
  <div>
    <div>
      <p style="margin:0px 0px 1.2em"></p>
      <div>
        <p></p>So, back to Attr -
        turns out that this code (of which I’m not very proud of :-) ),
        can be rewritted w/o accessing chk.basicHandler inside the anon
        class.</div></div></div></blockquote><div><br></div><div>Sure, you could do that - but that's really beside the point.</div><div><br></div><div>The point I'm making is simply to show that incidences of classes declared in early construction contexts accessing outer instances exist out there in the world. They may be rare, but they are not so rare that they can be dismissed - at least not according to the high Java/openjdk backward compatibility standards that I've observed over the years. Do you disagree?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div>Thinking more, I
        think I can perhaps find an argument in defense of the strategy
        of the approach outlined in the current JEP: migrating lambdas
        to classes.
      <p style="margin:0px 0px 1.2em">So, back to your
        example:</p>
      <pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);display:block;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"><span><span style="color:rgb(51,51,51);font-weight:bold">class</span> <span style="color:rgb(68,85,136);font-weight:bold">Outer</span>
    <span style="color:rgb(68,85,136);font-weight:bold">int</span> <span style="color:rgb(68,85,136);font-weight:bold">x</span></span>;
    <span><span style="color:rgb(51,51,51);font-weight:bold">class</span> <span style="color:rgb(68,85,136);font-weight:bold">Inner</span> <span style="color:rgb(51,51,51);font-weight:bold">extends</span> <span style="color:rgb(68,85,136);font-weight:bold">Foo</span> </span>{
        Inner() {
            <span style="color:rgb(51,51,51);font-weight:bold">super</span>(<span style="color:rgb(51,51,51);font-weight:bold">new</span> Bar() {
                { Outer.<span style="color:rgb(51,51,51);font-weight:bold">this</span>.x++; }   <span style="color:rgb(153,153,136);font-style:italic">// allowed???</span>
            });
        }
    }
}
</code></pre>
      <p style="margin:0px 0px 1.2em">Let’s say we write
        this using lambdas:</p>
      <pre style="font-family:Consolas,Inconsolata,Courier,monospace;font-size:1em;line-height:1.2em;margin:1.2em 0px"><code style="font-size:0.85em;font-family:Consolas,Inconsolata,Courier,monospace;margin:0px 0.15em;white-space:pre-wrap;overflow:auto;border-radius:3px;border:1px solid rgb(204,204,204);display:block;padding:0.5em;color:rgb(51,51,51);background:rgb(248,248,248)"> <span><span style="color:rgb(51,51,51);font-weight:bold">class</span> <span style="color:rgb(68,85,136);font-weight:bold">Outer</span>
     <span style="color:rgb(68,85,136);font-weight:bold">int</span> <span style="color:rgb(68,85,136);font-weight:bold">x</span></span>;
     <span><span style="color:rgb(51,51,51);font-weight:bold">class</span> <span style="color:rgb(68,85,136);font-weight:bold">Inner</span> <span style="color:rgb(51,51,51);font-weight:bold">extends</span> <span style="color:rgb(68,85,136);font-weight:bold">Foo</span> </span>{
         Inner() {
             <span style="color:rgb(51,51,51);font-weight:bold">super</span>(() -> { ... Outer.<span style="color:rgb(51,51,51);font-weight:bold">this</span>.x++ ... });
             });
         }
     }
 }
</code></pre>
      <p style="margin:0px 0px 1.2em">This is now ok, as
        the lambda has access to any enclosing instances that were
        available at the time the lambda was created (e.g. Outer.this).
      </p></div></div></blockquote><div>I'm not sure I understand... I don't see how an inner class vs. a lambda are any different with respect to how outer instances are handled or can be accessed. In both cases, the constructor is going to have to construct some object and pass as a synthetic parameter a copy of the synthetic "Outer.this" parameter provided to the Inner() constructor. In neither case can the constructor pass the Inner "this" instance at that time, because it is still uninitialized.<br></div><div><br></div><div>To be clear, here is how the JDK 17 compiler compiles the two variants of this class:</div><div><br></div><div style="margin-left:40px"><span style="font-family:monospace">import java.util.concurrent.atomic.AtomicReference;<br>class Outer {<br>     int x;<br>     class Inner extends AtomicReference<Runnable> {<br>         Inner() {<br>             super(new Runnable() { public void run() { Outer.this.x++; } });   // variant #1<br>             super(() -> Outer.this.x++);                                       // variant #2<br>         }<br>     }<br> }</span><br></div><div><br></div><div>Variant #1:</div><div><span style="font-family:monospace"><br></span></div><div style="margin-left:40px"><span style="font-family:monospace">  Outer$Inner(Outer);<br>    Code:<br>       0: aload_0<br>       1: aload_1<br>       2: putfield      #1                  // Field this$0:LOuter;<br>       5: aload_0<br>       6: new           #7                  // class Outer$Inner$1<br>       9: dup<br>      10: aload_1<br>      11: invokespecial #9                  // Method Outer$Inner$1."<init>":(LOuter;)V<br>      14: invokespecial #13                 // Method java/util/concurrent/atomic/AtomicReference."<init>":(Ljava/lang/Object;)V<br>      17: return<br></span></div><div><br></div><div>Variant #2:</div><div><br></div><div style="margin-left:40px"><span style="font-family:monospace">  Outer$Inner(Outer);<br>    Code:<br>       0: aload_0<br>       1: aload_1<br>       2: putfield      #1                  // Field this$0:LOuter;<br>       5: aload_0<br>       6: aload_1<br>       7: invokedynamic #7,  0              // InvokeDynamic #0:run:(LOuter;)Ljava/lang/Runnable;<br>      12: invokespecial #11                 // Method java/util/concurrent/atomic/AtomicReference."<init>":(Ljava/lang/Object;)V<br>      15: return</span><br></div><div><br></div><div>In both cases, the synthetic Outer.this passed to the Inner() constructor is in turn passed to the Runnable or lambda. In both cases it would be illegal to instead access <span style="font-family:monospace">this$0</span> directly.<br></div><div><br></div><div>-Archie<br></div></div><br><span class="gmail_signature_prefix">-- </span><br><div dir="ltr" class="gmail_signature">Archie L. Cobbs<br></div></div>