Skip to content

Align Scala 2.14 and 3.x trait initialization #642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
retronym opened this issue Jul 31, 2019 · 4 comments
Closed

Align Scala 2.14 and 3.x trait initialization #642

retronym opened this issue Jul 31, 2019 · 4 comments
Labels
dotty towards scala 3

Comments

@retronym
Copy link
Member

retronym commented Jul 31, 2019

Dotty has implemented a new encoding for trait constructors. Scala 2.14 and 3.0 should align on this implementation detail.

The alignment could come from:

  • Scala 2.14 adopting the new encoding
  • Scala 3.x reverting to the old encoding
  • Scala 3.x modifying the new encoding to allay concerns about binary fragility (discussion below), and Scala 2.x moving to the modified version.

Sample

trait T {
   println("1")
   val field1 = 1
   println("2")
   var field2 = 2
   println("3")
}
class C extends T

Scala 2.13

public class C
implements T {
    private int field1;
    private int field2;

    @Override
    public int field1() {
        return this.field1;
    }

    @Override
    public int field2() {
        return this.field2;
    }

    @Override
    public void field2_$eq(int x$1) {
        this.field2 = x$1;
    }

    @Override
    public void T$_setter_$field1_$eq(int x$1) {
        this.field1 = x$1;
    }

    public C() {
        T.$init$(this);
        Statics.releaseFence();
    }
}

public interface T {
    public void T$_setter_$field1_$eq(int var1);

    public int field1();

    public int field2();

    public void field2_$eq(int var1);

    public static void $init$(T $this) {
        Predef$.MODULE$.println((Object)"1");
        $this.T$_setter_$field1_$eq(1);
        Predef$.MODULE$.println((Object)"2");
        $this.field2_$eq(2);
        Predef$.MODULE$.println((Object)"3");
    }
}

Scala 3.x

public class C
implements T {
    private final int field1 = T.super.initial$field1();
    private int field2 = T.super.initial$field2();

    public C() {
        T.super.$init$();
    }

    @Override
    public int field1() {
        return this.field1;
    }

    @Override
    public int field2() {
        return this.field2;
    }

    @Override
    public void field2_$eq(int x$1) {
        this.field2 = x$1;
    }
}


public interface T {
    default public void $init$() {
        Predef$.MODULE$.println((Object)"3");
    }

    public int field1();

    default public int initial$field1() {
        Predef$.MODULE$.println((Object)"1");
        return 1;
    }

    public int field2();

    default public int initial$field2() {
        Predef$.MODULE$.println((Object)"2");
        return 2;
    }

    public void field2_$eq(int var1);
}

Advantages of new encoding

  • eager vals may be represented by JVM final fields. Scala 2's isn't able to do this because final fields assignments must appear lexically in the class constructor.

Binary fragility

Traits have a number of well-known binary fragilities. Most notably, when a field is added to a trait and a subclass is not recompiled, a LinkageError will happen when the trait constructor calls the trait setter.

The new encoding introduces new binary fragilities, one of which has a soft failure mode (execution order incorrect). This is because the subclass has the order of the fields "baked in" to its constructor which calls the intiaial$... methods sequentially.

Following are some failure modes when certain changes are made to the trait without recompiling the subclass.

Edit New Behaviour Old Behaviour
Fields or side effects reordered The subclass constructor will execute the old sequence of initialiation/effects. This could be benign but is dangerous in general No need to recompile subclass, semantics okay
Field deleted LinkageError wasted field in the subclass, but semantically okay

Modified, fail-fast encoding

@smarter Has suggested that we could encode the index of the initializer into the initial$... method names.

Edit New Behaviour
Fields or side effects reordered LinkageError
Field deleted LinkageError
@retronym retronym added this to the 2.14 milestone Jul 31, 2019
@retronym retronym added the dotty towards scala 3 label Jul 31, 2019
@lrytz
Copy link
Member

lrytz commented Jul 31, 2019

(the original Scala source code is missing in the description)

@retronym
Copy link
Member Author

@lrytz oops, fixed

@lrytz
Copy link
Member

lrytz commented Jul 31, 2019

I should have taken it as a reverse-engineering exercise 🙃

@SethTisue
Copy link
Member

out of scope for Scala 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dotty towards scala 3
Projects
None yet
Development

No branches or pull requests

3 participants