Wish list: Support inlined dispatch/combine calls
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
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...
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.
Should be careful with inlining because you don't want to produce too big trees 😄 But it could be a feature for expert users.
Can this wait until Scala 3?
Seems like it might happen automatically in 3 as long as user methods are inline