Reputation: 45735
I wonder if this can be done with scala macros
Consider this method:
def doSomething(filter: Item => Boolean) = ...
class Item(properties: Map[String, String]) extends Dynamic {
def selectDynamic(name:String): String = {
properties.getOrElse(name, "")
}
def updateDynamic(name: String)(value: String): Unit = {
addProperty(name, value)
}
}
And this usage
doSomething(x=> x.foo == "X" && x.bar == "Y" || x.baz.nonEmpty)
What I'd like to do is to simplify it (I'm writing a DSL for people who don't really use scala much) to this:
doSomething(foo == "X" && bar == "Y" || baz.nonEmpty)
My assumption is that even with Scala macros this might be impossible, or is it?
If so, where do I start? I assume this is not a simplistic macro...
Upvotes: 2
Views: 157
Reputation: 39577
You're right that the identifiers must be introduced.
In his ugliest code and worst pun on Metaplasm, Travis Brown called it "Potemkin val-age". A macro introduces the syntax machinery, which is imported before use (or abuse).
Potemkin definitions may not suit your use case if your property names are just arbitrary data.
Maybe something like this to collect the syntax, then a macro could operate on it (as opposed to the quickie conversion here).
case object is
object when extends Dynamic {
def applyDynamic(f: String)(op: Any) = new P(f, op)
}
case class P(f: String, op: Any) extends Dynamic {
def applyDynamic(op: String)(value: String) = Q(this, op, value)
}
case class Q(p: P, op: String, value: String)
object Test extends App {
implicit def `Q to filter`(q: Q): Item => Boolean = (i: Item) => (q.p.op, q.op) match {
case (is, "equal") => i.properties.get(q.p.f) map (_ == q.value) getOrElse false
case _ => false
}
val items = List (
Item(Map("foo" -> "X", "bar" -> "Y")),
Item(Map("this" -> "that")),
Item(Map("baz" -> "more"))
)
def doSomething(filter: Item => Boolean) = Console println (items filter filter)
doSomething(when foo is equal "X")
}
I didn't give Dynamic a thought until I saw this earlier today: https://stackoverflow.com/a/16256935/1296806
Upvotes: 3