Skip to content
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

Clean up interaction between module desugaring and mixin #42

Closed
retronym opened this issue Aug 20, 2015 · 9 comments
Closed

Clean up interaction between module desugaring and mixin #42

retronym opened this issue Aug 20, 2015 · 9 comments
Assignees
Milestone

Comments

@retronym
Copy link
Member

No description provided.

@retronym retronym self-assigned this Aug 20, 2015
@retronym
Copy link
Member Author

Current transform in mixin for:

trait T {
  object O
}

class C extends T

Is:

--- abstract trait T extends Object { (Selection)
+++ (clipboard)
@@ -1,17 +1,35 @@
+package <empty> {
   abstract trait T extends Object {
     <stable> def O(): T$O.type
   };
   class C extends Object with T {
+    @volatile <synthetic> private[this] var O$module: T$O.type = _;
+    private def O$lzycompute(): T$O.type = {
+      {
+        C.this.synchronized({
+          if (C.this.O$module.eq(null))
+            {
+              C.this.O$module = new T$O.type(C.this);
+              ()
+            };
+          scala.runtime.BoxedUnit.UNIT
+        });
+        null
+      };
+      C.this.O$module
+    };
+    <stable> def O(): T$O.type = if (C.this.O$module.eq(null))
+      C.this.O$lzycompute()
+    else
+      C.this.O$module;
     def <init>(): C = {
       C.super.<init>();
-      C.this.$asInstanceOf[T$class]()./*T$class*/$init$();
+      T$class./*T$class*/$init$(C.this);
       ()
     }
   };
-  abstract trait T$class extends Object with T {
-    @volatile <synthetic> var O$module: T$O.type = _;
-    <stable> def O(): T$O.type = new T$O.type(T$class.this);
-    def /*T$class*/$init$(): Unit = {
+  abstract trait T$class extends  {
+    def /*T$class*/$init$($this: T): Unit = {
       ()
     }
   };

@retronym
Copy link
Member Author

Quoth @lrytz:

hope the duplication between mixin and refchecks will go away https://github.com/scala/scala/blob/2.11.x/src/compiler/scala/tools/nsc/transform/Mixin.scala#L1086 / https://github.com/scala/scala/blob/2.11.x/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala#L1204)

this is generating the accessor for a nested module, in mixin we do it again in the mixin class

@retronym
Copy link
Member Author

@adriaanm
Copy link
Contributor

I was thinking if there was a way to reduce how much code we have to inject into every class that extends a trait, but synchronization and the second null check make it hard to imagine how.

@adriaanm
Copy link
Contributor

Ideally, the class would just have a field and trivially implement straight getter/setters.

@adriaanm
Copy link
Contributor

Maybe something like:

abstract trait T extends Object {
  <stable> def O(): T$O.type
  <stable> <notprivate> def O$module(): T$O.type
  private def O$lzycompute(): T$O.type = {
    val mod = O$module()
    if (mod eq null) new T$O.type(this)
    else mod
  }
}

class C extends Object with T {
  @volatile <synthetic> private[this] var O$module: T$O.type = _;
  <stable> <notprivate> def O$module(): T$O.type = C.this.O$module

  <stable> def O(): T$O.type = {
    if (C.this.O$module.eq(null))
      C.this.synchronized({ C.this.O$module = C.this.O$lzycompute() })

    C.this.O$module
  }
}

Not sure if it's worth it, or even if it meets the same criteria regarding bytecode size, JITability,...

@retronym
Copy link
Member Author

A variation:

abstract trait T extends Object {
  <stable> def O(): T$O.type = {
    val mod1 = T.this.O$module
    if (T.this.O$module.eq(null))
      T.this.synchronized {
        val mod2 = O$module()
        O$module_=(if (mod2 eq null) new T$O.type(this) else mod2)
      }
    else mod1

  <stable> <notprivate> def O$module(): T$O.type
  <notprivate> def O$module_=(o: T$O): Unit
}

class C extends Object with T {
  @volatile <synthetic> private[this] var O$module: T$O.type = _;
  <stable> <notprivate> def O$module(): T$O.type = C.this.O$module
  <notprivate> def O$module_=(o: T$O): Unit = this.O$module = o

}

I believe the semantics are the same, but it has the potential for worse performance. In the status quo, a call to def test(c: C) = c.O would not incur any invokeinterface calls.

@retronym
Copy link
Member Author

Here's a little progress: retronym/scala#18

@retronym
Copy link
Member Author

retronym commented Sep 5, 2015

scala/scala#4729

@retronym retronym added this to the 2.12.0-M4 milestone Apr 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants