On 28/04/17 09:58, Naftoli Gugenheim wrote:
> Not sure but I think quasiquotes are the safest.
>
> Are you sure it needs a macro? Do you want to describe in more detail what
> your ultimate goal is?
I think you may be right - I tried to figure out quasiquotes and after
reading some examples and then spending an age trying and failing to
find out what ".." and "..." did, I gave up. I also had a look at
scala.meta which I understand is supposed to replace the current macro
system, but it appears you need a build.sbt that's longer than the
program itself just to get it to compile...
What I'm trying to do is a variant on the hoary old "update a case class
from a map" problem. The wrinkles are that the map in question is an
akka-http-spray-json JsObject, namely a Map[String, JsValue] and the
JsObject fields and corresponding case class fields may have different
names.
If the JsObject contains a key corresponding to a case class field, I
want to copy the case class instance with the relevant field updated
with the value of the corresponding JsObject entry, otherwise I want the
unmodified case class instance back. Here's what I have so far:
def makeUpdater[C, T](obj: C, params: JsObject)(updater: (C, T) => C,
key: String)
(implicit jr: JsonReader[T]): C = {
params.fields.get(key) match {
case Some(v) => updater(obj, v.convertTo[T])
case None => obj
}
}
Note that has three argument lists, the last one is to pick up an
implicit JsonReader for doing the convertTo call, the intent of the
first and second are so that you can do something along the lines of:
val json: JsObject = ...
var props = ... // Some case class
def update = makeUpdater(props, json) _
props = update((p, v) => p.copy(loginName = v), "login_name")
props = update((p, v) => p.copy(password = v), "passwd")
except that doesn't actually work :-(
Error:(210, 29) Cannot find JsonReader or JsonFormat type class for Nothing
def update = makeUpdater(props, json) _
I believe that's because the compiler can't resolve the type of T, and
therefore it also can't find the correct implicit JsonReader.
This on the other hand *does* work:
props = makeUpdater(props, json)((p, v) => p.copy(loginName = v),
"login_name")
What I want is for partial application of makeUpdater to preserve the
generic nature of T, but I can't figure out if that's possible or not.
Something along the lines of:
def makeUpdater[C, T](obj: C, params: JsObject)(updater[T]: (C, T) => C,
key: String)
but of course that's syntactically invalid. I suspect there may be a way
of doing this, I just can't figure out what it is.
The original reason of looking at macros for a solution is because the
operation itself seemed simple - if the JsObject map contains the key,
get the value, convert it with the corresponding JsReader and pass to
the case class object's copy method. If it doesn't, return the original
case class instance.
--
Alan Burlison
--