I need to replace some simple boilerplate - nothing that would tax even
a C preprocessor - but it's unclear what variant of Scala's macro support I should use. Much of the macro information on scala-lang.org appears to be out of date and/or contradictory. What should I be using for a simple macro use case that will be relatively future-proof? Thanks, -- Alan Burlison -- -- You received this message because you are subscribed to the Google Groups "scala-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
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? On Wed, Apr 26, 2017 at 11:54 AM Alan Burlison <[hidden email]> wrote: I need to replace some simple boilerplate - nothing that would tax even You received this message because you are subscribed to the Google Groups "scala-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
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 -- -- You received this message because you are subscribed to the Google Groups "scala-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Hi, The nature of the problem stems from the fact that functions can't have implicit parameter lists, so when you partially apply it, the compiler is forced to resolve the implicit, and since you second parameter is not present it resolves to nothing.def makeUpdater[C](obj: C, params: JsObject) = new Updater(obj, params) class Updater[C](obj: C, params: JsObject) { def apply[T](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 } } Usage would then be: 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") Cheers. On Fri, Apr 28, 2017 at 10:43 AM, Alan Burlison <[hidden email]> wrote: On 28/04/17 09:58, Naftoli Gugenheim wrote: You received this message because you are subscribed to the Google Groups "scala-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
On 28/04/17 18:09, Rodrigo Cano wrote:
> The nature of the problem stems from the fact that functions can't have > implicit parameter lists, so when you partially apply it, the compiler is > forced to resolve the implicit, and since you second parameter is not > present it resolves to nothing. Ah, that makes sense, thanks for the explanation. > However, there is a trick you can pull to have a sort of two staged type > resolution for you partially applied method, using an intermediate class > with an apply method. Something along the lines of > > def makeUpdater[C](obj: C, params: JsObject) = new Updater(obj, params) > class Updater[C](obj: C, params: JsObject) { > def apply[T](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 > } > } Oh, that's a neat trick that I'd never have thought of :-) > Usage would then be: > > 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") Only one small tweak needed, the addition of the type of the case class field being assigned to: props = update[String]((p, v) => p.copy(loginName = v), "login_name") I'd have thought the compiler could have inferenced that, but apparently not. Thanks for the help, much appreciated :-) -- Alan Burlison -- -- You received this message because you are subscribed to the Google Groups "scala-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email]. For more options, visit https://groups.google.com/d/optout. |
Free forum by Nabble | Edit this page |