(for TL;DR, go to the bold face part)
I am having a clean closed type class system with serialization (detached from POJO serialization woes). For example:
trait Expr
case class Const(i: Int) extends Expr
case class BinOp(a: Expr, b: Expr, op: Int) extends Expr
But in situations I need to capture a closure. For example:
case class Map(a: Expr, fun: Expr => Expr) extends Expr
Now, I had solved this once with POJO serialization (ObjectOutputStream
etc.) for the fun
. I got badly bitten in the feet, because I couldn't read in Scala 2.10 what I had serialised in 2.9. And in this case, I really need to make sure I can get my stuff back independent of the Scala version.
So... I have been thinking that I could use a macro to make a "backup" of the source code, so that if POJO deserialisation fails, I can regenerate the function from source (using an in-place compiler/interpreter).
My idea would be
object Map {
def apply(a: Expr, fun: Expr => Expr): Map = macro applyImpl
private def applyImpl = ???
def unapply(m: Map): Option[(Expr, Expr => Expr)] = Some(m.a -> m.fun)
}
trait Map extends Expr {
def a: Expr
def fun: Expr => Expr
}
implicit class ExprOps(val ex: Expr) extends AnyVal {
def map(fun: Expr => Expr) = Map(ex, fun)
}
Is it possibly to easily capture the source of a call like
// |------------- source of this -------------|
someExpr.map { case Const(i) => Const(i*i); case x => x }
(My guess is the def-macro needs to be already in the map
function of ExprOps
).