Closed
Description
trait T {
case object Foo
}
object Bar extends T
object Test {
def main(args: Array[String]): Unit = {
assert(Bar.Foo == Bar.Foo) // false
}
}
Looking at the bytecode we see than Bar.Foo
calls T.Foo
which creates a new instance on every call:
public interface T {
default public void $init$() {
}
default public Foo. Foo() {
return new Foo.();
}
}
public final class Bar$
implements T {
public static final Bar$ MODULE$;
public static {
new Bar$();
}
public Bar$() {
MODULE$ = this;
}
@Override
public final T.Foo. Foo() {
return T.super.Foo();
}
}
For comparison, this the code generated by scalac:
public interface T {
public Foo. Foo();
default public static void $init$(T $this) {
}
}
public final class Bar$
implements T {
public static Bar$ MODULE$;
private volatile T.Foo. Foo$module;
public static {
new Bar$();
}
@Override
public T.Foo. Foo() {
if (this.Foo$module == null) {
this.Foo$lzycompute$1();
}
return this.Foo$module;
}
private final void Foo$lzycompute$1() {
Bar$ bar$ = this;
synchronized (bar$) {
if (this.Foo$module == null) {
this.Foo$module = new T.Foo.(null);
}
}
}
private Bar$() {
MODULE$ = this;
T.$init$(this);
}
}