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

Wish list: Support inlined dispatch/combine calls #238

Open
neko-kai opened this issue Apr 21, 2020 · 5 comments
Open

Wish list: Support inlined dispatch/combine calls #238

neko-kai opened this issue Apr 21, 2020 · 5 comments

Comments

@neko-kai
Copy link
Contributor

neko-kai commented Apr 21, 2020

Theoretically it may be possible to generalize CaseClass/SealedTrait structures to put trees in there instead of runtime values and parameterize the Magnolia macro with dispatch/combine before creating the macro, e.g.

trait MyTC[A] {
  def toMap(a: A): Map[String, String]
}
object MyTC {
  def derived[A] = macro MyMagnoliaDeriver.gen[A]
}

object MyMagnoliaDeriver {
  def gen[A: c.WeakTypeTag](c: whitebox.Context): c.Expr[MyTC[A]] = {
    Magnolia.hypotheticalGenWith[MyTC[A]](combine[A](c), dispatch[A](c))
  }

  def combine[Type: c.WeakTypeTag](c: whitebox.Context)(
    caseclass: CaseClass[c.Expr, MyTC, Type]
  ): c.Expr[MyTC[Type]] = {
    import c.universe._
    val arg = c.Expr[Type](TermName("arg"))
    val exprs = ctx.parameters.map { p =>
      reify { p.label.splice -> p.typeclass.splice.toMap(p.dereference(arg).splice) }
    }.toList
    val listExprs = c.Expr[List[(String, String)]] = q"$exprs"
    reify { 
      new TC[Type] {
        def toMap(arg: Type) = listExprs.splice.toMap
      }
    }
  }

  def dispatch = ...
}

This would allow to remove all the runtime cost for the creation of CaseClass/SealedTrait structures & inline all the information directly into the generated codecs

@propensive
Copy link
Collaborator

I might need a bit longer to work out the implications of this... have you any idea what the runtime performance improvement might be? Obviously it would depend on what typeclass we're deriving, but a side-by-side comparison of a hand-rolled version of the derivation we could expect from this inlining against Magnoia's current derivation would be interesting...

@neko-kai
Copy link
Contributor Author

neko-kai commented Apr 23, 2020

The point is to generate the exact same code for an instance as you would write if you hand-rolled it. Because you can output arbitrary trees in these functions you can optimize as much as you please - the difference is that you get some tricky reflection work pre-done and packed nicely into data types by Magnolia.

@joroKr21
Copy link
Contributor

Should be careful with inlining because you don't want to produce too big trees 😄
But it could be a feature for expert users.

@propensive
Copy link
Collaborator

Can this wait until Scala 3?

@neko-kai
Copy link
Contributor Author

neko-kai commented Dec 7, 2020

Seems like it might happen automatically in 3 as long as user methods are inline

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

3 participants