Closed
Description
Noticed in #1691 — scalac, but not dotty (as pointed out by @smarter), compiles the following so the initializer for byLazyValMsg
clears byNameMsg
. This is not just an optimization, but is needed for correctness to prevent memory leaks:
class TestByNameLazy(byNameMsg: => String) {
lazy val byLazyValMsg = byNameMsg
}
Resulting code with Scalac (as decompiled with jad)—note byName = null;
:
public class TestByNameLazy
{
private String byLVal$lzycompute()
{
synchronized(this)
{
if(!bitmap$0)
{
byLVal = (String)byName.apply();
bitmap$0 = true;
}
BoxedUnit _tmp = BoxedUnit.UNIT;
}
byName = null;
return byLVal;
}
public String byLVal()
{
return bitmap$0 ? byLVal : byLVal$lzycompute();
}
public TestByNameLazy(Function0 byName)
{
this.byName = byName;
super();
}
private final Function0 byName;
private String byLVal;
private volatile boolean bitmap$0;
}
Is this documented anywhere?
Maybe but not to my knowledge; I've seen similar patterns often enough and Dragos described this in scala/scala#922 as:
Less known fact: lazy values null-out their dependent values is they're accessed only from
their initializer.
I found that PR by searching JIRA https://issues.scala-lang.org/browse/SI-6092 (which is not about this "feature" missing altogether, just about a bug with it).