<!DOCTYPE html><html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div class="markdown-here-wrapper" data-md-url="" style="" markdown-here-wrapper-content-modified="true">
<p style="margin: 0px 0px 1.2em !important;">On 22/10/2024 19:35,
Archie Cobbs wrote:</p>
<p style="margin: 0px 0px 1.2em !important;"></p>
<div class="markdown-here-exclude">
<p></p>
<blockquote type="cite" cite="mid:CANSoFxswVHJDf66i50fJp1DY-FK0V0FnHv+swuKKZZWrbUqDvQ@mail.gmail.com">This
made me realize this issue really is all just about naming.
For example, outer instances are captured just like variables,
but we don't have a problem there because the captured version
of the variable has a different name inside the nested class
vs. outside (i.e., "Outer.this" vs. "outer", if you create the
nested class via "outer.new Inner()").</blockquote>
<p></p>
</div>
<p style="margin: 0px 0px 1.2em !important;"></p>
<p style="margin: 0px 0px 1.2em !important;">I think this
observation hits the nails on the head.</p>
<p style="margin: 0px 0px 1.2em !important;">When we capture
“fields” we don’t really capture mutable boxes, we capture an
(immutable) reference to the enclosing class.</p>
<p style="margin: 0px 0px 1.2em !important;">I say immutable
because the enclosing class reference is snapshotted, at
construction - e.g. if you have:</p>
<pre style="font-size: 0.85em; font-family: Consolas, Inconsolata, Courier, monospace;font-size: 1em; line-height: 1.2em;margin: 1.2em 0px;"><code class="hljs language-java" style="font-size: 0.85em; font-family: Consolas, Inconsolata, Courier, monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;white-space: pre; overflow: auto; border-radius: 3px; border: 1px solid rgb(204, 204, 204); padding: 0.5em 0.7em; display: block !important;display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); background: rgb(248, 248, 248); -moz-text-size-adjust: none;">Outer outer = <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">new</span> Outer(); <span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// 1</span>
Outer.Inner inner = outer.<span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">new</span> Inner();
outer = <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">new</span> Outer(); <span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// 2</span>
</code></pre>
<p style="margin: 0px 0px 1.2em !important;">This is all legal
code. One might wonder: does this code mean that Inner’s
enclosing instance is updated in (2)? No, because, really, it’s
as if the value of “outer” was snapshotted when we created
Inner, and a reference to that snapshotted value was saved.
Since we access that snapshotted reference using <code style="font-size: 0.85em; font-family: Consolas, Inconsolata, Courier, monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">Outer.this</code>
(and not <code style="font-size: 0.85em; font-family: Consolas, Inconsolata, Courier, monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">outer</code>),
we sort of preserve the illusion that snapshotting doesn’t occur
here - the class is accessing its “enclosing instance” which is
a separate thing from a “field defined in the enclosing class”.</p>
<p style="margin: 0px 0px 1.2em !important;">So yes, a big part of
this exercise is in trying to keep variable names meaning the
same thing no matter where they appear (captured or not). If we
start snapshotting everything, then you have two version of a
local, the one snapshotted and captured e.g. inside a lambda,
and the one (maybe mutable!) available outside.</p>
<p style="margin: 0px 0px 1.2em !important;">My subjective opinion
here is that, if this principle is important (and, as John
mentioned, it was very painfully front and center when inner
classes were first added to the language), giving this principle
up to allow capture in an extra 20-30 imperative loops (in an
entire codebase) doesn’t look a great deal. That is, reducing
asymmeties between counted loops and for-each loop comes at a
price: now capture variables no longer mean the same thing they
do in their non-captured context.</p>
<p style="margin: 0px 0px 1.2em !important;">Of course you can
argue it both ways: by making the new capture treatment only
available for induction variables in for loops (where the
variable is not mutated in the body) we do reduce (not
eliminate!) the chances of somebody observing different values
for the same induction variable. Is that enough to put our minds
at ease? Overall, it seems to me that this a very subjective
topic: there is no well-defined principle as to why imperative
for loops should behave any different than they do today, as
there is (likely) no well-defined principle as to why for-each
loop behaves the way it does today. </p>
<p style="margin: 0px 0px 1.2em !important;">How you "fix" this
largely depends on (a) how you find this asymmetry annoying
(which likely depends on exposure - and different code bases
might have different levels of that) and (b) how much your
developer intuition is trained to view the loop induction
variable as a single mutable *variable*, or a series of *values*
where each value is derived from the former in a controlled
fashion. I don't have a strong (enough) opinion on either :-)<br>
</p>
<p style="margin: 0px 0px 1.2em !important;">Maurizio</p>
<div title="MDH:PHA+PGJyPjwvcD48ZGl2IGNsYXNzPSJtb3otY2l0ZS1wcmVmaXgiPk9uIDIyLzEwLzIwMjQgMTk6
MzUsIEFyY2hpZSBDb2JicyB3cm90ZTo8YnI+PC9kaXY+PGJsb2NrcXVvdGUgdHlwZT0iY2l0ZSIg
Y2l0ZT0ibWlkOkNBTlNvRnhzd1ZISkRmNjZpNTBmSnAxRFktRkswVjBGbkh2K3N3dUtLWlpXcmJV
cUR2UUBtYWlsLmdtYWlsLmNvbSI+VGhpcyBtYWRlIG1lIHJlYWxpemUgdGhpcyBpc3N1ZSByZWFs
bHkgaXMgYWxsIGp1c3QgYWJvdXQgbmFtaW5nLiBGb3IgCmV4YW1wbGUsIG91dGVyIGluc3RhbmNl
cyBhcmUgY2FwdHVyZWQganVzdCBsaWtlIHZhcmlhYmxlcywgYnV0IHdlIGRvbid0IApoYXZlIGEg
cHJvYmxlbSB0aGVyZSBiZWNhdXNlIHRoZSBjYXB0dXJlZCB2ZXJzaW9uIG9mIHRoZSB2YXJpYWJs
ZSBoYXMgYSAKZGlmZmVyZW50IG5hbWUgaW5zaWRlIHRoZSBuZXN0ZWQgY2xhc3MgdnMuIG91dHNp
ZGUgKGkuZS4sICJPdXRlci50aGlzIiAKdnMuICJvdXRlciIsIGlmIHlvdSBjcmVhdGUgdGhlIG5l
c3RlZCBjbGFzcyB2aWEgIm91dGVyLm5ldyBJbm5lcigpIikuPC9ibG9ja3F1b3RlPjxwPkkgdGhp
bmsgdGhpcyBvYnNlcnZhdGlvbiBoaXRzIHRoZSBuYWlscyBvbiB0aGUgaGVhZC48L3A+PHA+V2hl
biB3ZSBjYXB0dXJlICJmaWVsZHMiIHdlIGRvbid0IHJlYWxseSBjYXB0dXJlIG11dGFibGUgYm94
ZXMsIHdlIGNhcHR1cmUgYW4gKGltbXV0YWJsZSkgcmVmZXJlbmNlIHRvIHRoZSBlbmNsb3Npbmcg
Y2xhc3MuPC9wPjxwPkkgc2F5IGltbXV0YWJsZSBiZWNhdXNlIHRoZSBlbmNsb3NpbmcgY2xhc3Mg
cmVmZXJlbmNlIGlzIHNuYXBzaG90dGVkLCBhdCBjb25zdHJ1Y3Rpb24gLSBlLmcuIGlmIHlvdSBo
YXZlOjwvcD48cD5gYGBqYXZhPGJyPk91dGVyIG91dGVyID0gbmV3IE91dGVyKCk7IC8vIDE8YnI+
T3V0ZXIuSW5uZXIgaW5uZXIgPSBvdXRlci5uZXcgSW5uZXIoKTs8YnI+b3V0ZXIgPSBuZXcgT3V0
ZXIoKTsgLy8gMjxicj5gYGA8L3A+PHA+VGhpcyBpcyBhbGwgbGVnYWwgY29kZS4gT25lIG1pZ2h0
IHdvbmRlcjogZG9lcyB0aGlzIGNvZGUgbWVhbiB0aGF0IElubmVyJ3MgZW5jbG9zaW5nIGluc3Rh
bmNlIGlzIHVwZGF0ZWQgaW4gKDIpPyBObywgYmVjYXVzZSwgcmVhbGx5LCBpdCdzIGFzIGlmIHRo
ZSB2YWx1ZSBvZiAib3V0ZXIiIHdhcyBzbmFwc2hvdHRlZCB3aGVuIHdlIGNyZWF0ZWQgSW5uZXIs
IGFuZCBhIHJlZmVyZW5jZSB0byB0aGF0IHNuYXBzaG90dGVkIHZhbHVlIHdhcyBzYXZlZC4gU2lu
Y2Ugd2UgYWNjZXNzIHRoYXQgc25hcHNob3R0ZWQgcmVmZXJlbmNlIHVzaW5nIGBPdXRlci50aGlz
YCAoYW5kIG5vdCBgb3V0ZXJgKSwgd2Ugc29ydCBvZiBwcmVzZXJ2ZSB0aGUgaWxsdXNpb24gdGhh
dCBzbmFwc2hvdHRpbmcgZG9lc24ndCBvY2N1ciBoZXJlIC0gdGhlIGNsYXNzIGlzIGFjY2Vzc2lu
ZyBpdHMgImVuY2xvc2luZyBpbnN0YW5jZSIgd2hpY2ggaXMgYSBzZXBhcmF0ZSB0aGluZyBmcm9t
IGEgImZpZWxkIGRlZmluZWQgaW4gdGhlIGVuY2xvc2luZyBjbGFzcyIuPC9wPjxwPlNvIHllcywg
YSBiaWcgcGFydCBvZiB0aGlzIGV4ZXJjaXNlIGlzIGluIHRyeWluZyB0byBrZWVwIHZhcmlhYmxl
IG5hbWVzIG1lYW5pbmcgdGhlIHNhbWUgdGhpbmcgbm8gbWF0dGVyIHdoZXJlIHRoZXkgYXBwZWFy
IChjYXB0dXJlZCBvciBub3QpLiBJZiB3ZSBzdGFydCBzbmFwc2hvdHRpbmcgZXZlcnl0aGluZywg
dGhlbiB5b3UgaGF2ZSB0d28gdmVyc2lvbiBvZiBhIGxvY2FsLCB0aGUgb25lIHNuYXBzaG90dGVk
IGFuZCBjYXB0dXJlZCBlLmcuIGluc2lkZSBhIGxhbWJkYSwgYW5kIHRoZSBvbmUgKG1heWJlIG11
dGFibGUhKSBhdmFpbGFibGUgb3V0c2lkZS48L3A+PHA+TXkgc3ViamVjdGl2ZSBvcGluaW9uIGhl
cmUgaXMgdGhhdCwgaWYgdGhpcyBwcmluY2lwbGUgaXMgaW1wb3J0YW50IChhbmQsIGFzIEpvaG4g
bWVudGlvbmVkLCBpdCB3YXMgdmVyeSBwYWluZnVsbHkgZnJvbnQgYW5kIGNlbnRlciB3aGVuIGlu
bmVyIGNsYXNzZXMgd2VyZSBmaXJzdCBhZGRlZCB0byB0aGUgbGFuZ3VhZ2UpLCBnaXZpbmcgdGhp
cyBwcmluY2lwbGUgdXAgdG8gYWxsb3cgY2FwdHVyZSBpbiBhbiBleHRyYSAyMC0zMCBpbXBlcmF0
aXZlIGxvb3BzIChpbiBhbiBlbnRpcmUgY29kZWJhc2UpIGRvZXNuJ3QgbG9vayBhIGdyZWF0IGRl
YWwuIFRoYXQgaXMsIHJlZHVjaW5nIGFzeW1tZXRpZXMgYmV0d2VlbiBjb3VudGVkIGxvb3BzIGFu
ZCBmb3ItZWFjaCBsb29wIGNvbWVzIGF0IGEgcHJpY2U6IG5vdyBjYXB0dXJlIHZhcmlhYmxlcyBu
byBsb25nZXIgbWVhbiB0aGUgc2FtZSB0aGluZyB0aGV5IGRvIGluIHRoZWlyIG5vbi1jYXB0dXJl
ZCBjb250ZXh0LjwvcD48cD5PZiBjb3Vyc2UgeW91IGNhbiBhcmd1ZSBpdCBib3RoIHdheXM6IGJ5
IG1ha2luZyB0aGUgbmV3IGNhcHR1cmUgdHJlYXRtZW50IG9ubHkgYXZhaWxhYmxlIGZvciBpbmR1
Y3Rpb24gdmFyaWFibGVzIGluIGZvciBsb29wcyAod2hlcmUgdGhlIHZhcmlhYmxlIGlzIG5vdCBt
dXRhdGVkIGluIHRoZSBib2R5KSB3ZSBkbyByZWR1Y2UgKG5vdCBlbGltaW5hdGUhKSB0aGUgY2hh
bmNlcyBvZiBzb21lYm9keSBvYnNlcnZpbmcgZGlmZmVyZW50IHZhbHVlcyBmb3IgdGhlIHNhbWUg
aW5kdWN0aW9uIHZhcmlhYmxlLiBJcyB0aGF0IGVub3VnaCB0byBwdXQgb3VyIG1pbmRzIGF0IGVh
c2U/IE92ZXJhbGwsIGl0IHNlZW1zIHRvIG1lIGEgdmVyeSBzdWJqZWN0aXZlIHRvcGljLjwvcD48
cD5NYXVyaXppbzxicj48L3A+PHA+PGJyPjwvcD48cD48YnI+PC9wPjxwPiZuYnNwOzxicj48L3A+
PHA+PGJyPjwvcD48cD48YnI+PC9wPjxwPjxicj48L3A+" style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0;"></div>
</div>
</body>
</html>