Skip to content

Specialize generics for value classes #2073

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
japgolly opened this issue Mar 10, 2017 · 7 comments
Closed

Specialize generics for value classes #2073

japgolly opened this issue Mar 10, 2017 · 7 comments

Comments

@japgolly
Copy link
Contributor

Using a fixpoint types, every node in the tree becomes boxed.

It would be great if Fix could be made a value class.

final case class Fix[F[_]](unfix: F[Fix[F]]) extends AnyVal
@odersky
Copy link
Contributor

odersky commented Mar 12, 2017

The line as given is compiled fine by dotty. Is there something else that does not work?

DarkDimius added a commit to dotty-staging/dotty that referenced this issue Mar 13, 2017
@DarkDimius
Copy link
Contributor

I've added a test that will make sure that this code keep compiling.

@japgolly
Copy link
Contributor Author

I just tested this with:

final case class Fix[F[_]](unfix: F[Fix[F]]) extends AnyVal

sealed trait Calc[+A]
case class Num(n: Int) extends Calc[Nothing]
case class Add[A](a: A, b: A) extends Calc[A]

object X {
  def c: Fix[Calc] =
    Fix[Calc](Add(
      Fix[Calc](Num(1)),
      Fix[Calc](Num(3))))
}

and the bytecode is:

  public java.lang.Object c();
    Code:
       0: getstatic     #23                 // Field Fix$.MODULE$:LFix$;
       3: getstatic     #28                 // Field Add$.MODULE$:LAdd$;
       6: new           #30                 // class Fix
       9: dup
      10: getstatic     #23                 // Field Fix$.MODULE$:LFix$;
      13: getstatic     #35                 // Field Num$.MODULE$:LNum$;
      16: iconst_1
      17: invokevirtual #39                 // Method Num$.apply:(I)LNum;
      20: invokevirtual #42                 // Method Fix$.apply:(Ljava/lang/Object;)Ljava/lang/Object;
      23: invokespecial #45                 // Method Fix."<init>":(Ljava/lang/Object;)V
      26: new           #30                 // class Fix
      29: dup
      30: getstatic     #23                 // Field Fix$.MODULE$:LFix$;
      33: getstatic     #35                 // Field Num$.MODULE$:LNum$;
      36: iconst_3
      37: invokevirtual #39                 // Method Num$.apply:(I)LNum;
      40: invokevirtual #42                 // Method Fix$.apply:(Ljava/lang/Object;)Ljava/lang/Object;
      43: invokespecial #45                 // Method Fix."<init>":(Ljava/lang/Object;)V
      46: invokevirtual #48                 // Method Add$.apply:(Ljava/lang/Object;Ljava/lang/Object;)LAdd;
      49: invokevirtual #42                 // Method Fix$.apply:(Ljava/lang/Object;)Ljava/lang/Object;
      52: areturn

The value class is being instantiated.
It would be awesome if the resulting bytecode were:

  public Calc c();
    Code:
       0: getstatic     #23                 // Field Add$.MODULE$:LAdd$;
       3: getstatic     #28                 // Field Num$.MODULE$:LNum$;
       6: iconst_1
       7: invokevirtual #32                 // Method Num$.apply:(I)LNum;
      10: getstatic     #28                 // Field Num$.MODULE$:LNum$;
      13: iconst_3
      14: invokevirtual #32                 // Method Num$.apply:(I)LNum;
      17: invokevirtual #35                 // Method Add$.apply:(Ljava/lang/Object;Ljava/lang/Object;)LAdd;
      20: areturn

@japgolly
Copy link
Contributor Author

@odersky @DarkDimius should we reopen this ticket for the above, or should I create a separate one?

@DarkDimius
Copy link
Contributor

DarkDimius commented Mar 16, 2017

@japgolly, The feature that your example needs to compile to efficient code is value-class specialization of Add. We have discussed a possible implementation idea in linker but it is very far from our current roadmap.

Currently, without value-class specialization, your optimized code has different semantics.
Let me illustrate this by having a slightly modified versions of add and Fix:

case class Add[A](a: A, b: A) extends Calc[A]{
 println(a.toString) // change
}

final case class Fix[F[_]](unfix: F[Fix[F]]) extends AnyVal {
  def toString() = "fix" // change
}

Which toString should Add call? in the bytecode you're suggesting the constructor argument of Add a will be passed unboxed and toString will be called on the a.unfix instead, which will not behave as Fix.toString.

@DarkDimius DarkDimius changed the title Permit recursive value classes Specialize generics for value classes Mar 16, 2017
@DarkDimius DarkDimius reopened this Mar 16, 2017
@japgolly
Copy link
Contributor Author

@DarkDimius Ah of course, I didn't even think about specialisation! So this will most likely be solved by Linker and WPO later?

@smarter
Copy link
Member

smarter commented Jan 11, 2018

Closing with stat:revisit since specialization isn't likely to come to Dotty soon.

@smarter smarter closed this as completed Jan 11, 2018
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

4 participants