Skip to content

Objects in traits are instantiated on every access #3624

Closed
@OlivierBlanvillain

Description

@OlivierBlanvillain
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);
    }
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions