Enumeration.values adds a value to set when called twice? - scala

scala> object Foo extends Enumeration {
| val Bar = Value(23)
| val Moo = Value(57)
| }
defined module Foo
scala> Foo.values
res27: Foo.ValueSet = Foo.ValueSet(Bar, Moo)
So far as expected. But then (continuing from above):
scala> Foo.values
res28: Foo.ValueSet = Foo.ValueSet(Bar, Moo, Value)
What just happened?

This is a bug in Scala 2.8.1. See the issue on JIRA.

Related

Evalutate complex type with quasiquote scala, unlifting

I need to compile function and then evaluate it with different parameters of type List[Map[String, AnyRef]].
I have the following code that does not compile with such the type but compiles with simple type like List[Int].
I found that there are just certain implementations of Liftable in scala.reflect.api.StandardLiftables.StandardLiftableInstances
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
object FunctionWrapper {
def makeBody(messages: List[Map[String, AnyRef]]) = Map.empty
}""".stripMargin
val functionSymbol =
tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
tb.eval(q"$functionSymbol.function($list)")
Getting compilation error for this, how can I make it work?
Error:(22, 38) Can't unquote List[Map[String,AnyRef]], consider using
... or providing an implicit instance of
Liftable[List[Map[String,AnyRef]]]
tb.eval(q"$functionSymbol.function($list)")
^
The problem comes not from complicated type but from the attempt to use AnyRef. When you unquote some literal, it means you want the infrastructure to be able to create a valid syntax tree to create an object that would exactly match the object you pass. Unfortunately this is obviously not possible for all objects. For example, assume that you've passed a reference to Thread.currentThread() as a part of the Map. How it could possible work? Compiler is just not able to recreate such a complicated object (not to mention making it the current thread). So you have two obvious alternatives:
Make you argument also a Tree i.e. something like this
def testTree() = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
| object FunctionWrapper {
|
| def makeBody(messages: List[Map[String, AnyRef]]) = Map.empty
|
| }
""".stripMargin
val functionSymbol =
tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
//val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
val list = q"""List(Map("1" -> "2"))"""
val res = tb.eval(q"$functionSymbol.makeBody($list)")
println(s"testTree = $res")
}
The obvious drawback of this approach is that you loose type safety at compile time and might need to provide a lot of context for the tree to work
Another approach is to not try to pass anything containing AnyRef to the compiler-infrastructure. It means you create some function-like Wrapper:
package so {
trait Wrapper {
def call(args: List[Map[String, AnyRef]]): Map[String, AnyRef]
}
}
and then make your generated code return a Wrapper instead of directly executing the logic and call the Wrapper from the usual Scala code rather than inside compiled code. Something like this:
def testWrapper() = {
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
val functionWrapper =
"""
|object FunctionWrapper {
| import scala.collection._
| import so.Wrapper /* <- here probably different package :) */
|
| def createWrapper(): Wrapper = new Wrapper {
| override def call(args: List[Map[String, AnyRef]]): Map[String, AnyRef] = Map.empty
| }
|}
| """.stripMargin
val functionSymbol = tb.define(tb.parse(functionWrapper).asInstanceOf[tb.u.ImplDef])
val list: List[Map[String, AnyRef]] = List(Map("1" -> "2"))
val tree: tb.u.Tree = q"$functionSymbol.createWrapper()"
val wrapper = tb.eval(tree).asInstanceOf[Wrapper]
val res = wrapper.call(list)
println(s"testWrapper = $res")
}
P.S. I'm not sure what are you doing but beware of performance issues. Scala is a hard language to compile and thus it might easily take more time to compile your custom code than to run it. If performance becomes an issue you might need to use some other methods such as full-blown macro-code-generation or at least caching of the compiled code.

scala - insert value into quasiquote

Unfortunately, the most intuitive way,
val world = "Earth"
val tree = q"""println("Hello $world")"""
results in
Error:(16, 36) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
because $ within quasiquotes expects a tree.
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
works, but is very ugly AND I get an Intellij warning that the c.literal is deprecated and I should use quasiquotes, instead.
So ... how do I do this?
UPDATE
In response to flavian's comment:
import scala.language.experimental.macros
import scala.reflect.macros._
object TestMacros {
def doTest() = macro impl
def impl(c: blackbox.Context)(): c.Expr[Unit] = {
import c.universe._ //access to AST classes
/*
val world = "Earth"
val tree = q"""println(${c.literal(s"Hello $world")})"""
*/
val world = TermName("Earth")
val tree = q"""println("Hello $world")"""
tree match {
case q"""println("Hello Earth")""" => println("succeeded")
case _ => c.abort(c.enclosingPosition, s"huh? was: $tree")
}
c.Expr(tree) //wrap tree and tag with its type
}
}
gives
Error:(18, 40) Don't know how to unquote here
val tree = q"""println("Hello $world")"""
^
You need a TermName or something that's a compiler primitive.
The real problem is that you are mixing interpolators, without realising. The interpolator in hello world is really a string interpolator, not a quasiquote one which is good at unquoting trees as you suggest.
This is one way to go about it:
import c.universe._
val world = TermName("Earth")
val tree = q"""println("Hello" + ${world.decodedName.toString})"""
I just started learning Macro-Fu.
For those also exploring Scala 2 Macros / Scalameta Quasiquotes, seems to me the simplest approach is the following (using SBT 1.5.5; inline explanations):
scala> import scala.language.experimental.macros
| import scala.reflect.macros.blackbox
|
| object UnquoteString {
|
| def helloWorld(): Unit = macro Impl.helloWorld
|
| object Impl {
| def helloWorld(c: blackbox.Context)(): c.Expr[Unit] = {
| import c.universe._
|
| val world = "Earth" // or any other value here...
|
| val msg = s"Hello $world" // build the entire string with it here...
|
| implicitly[Liftable[String]] // as we can lift 'whole' string values with this Liftable[_]...
|
| val tree = q"""println($msg)""" // quasi-unquote the entire string here...
|
| c.Expr[Unit](Block(Nil, tree))
| }
| }
| }
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object UnquoteString
scala> UnquoteString.helloWorld()
Hello Earth
scala>
Also the following change would also work
val tree = q"""println("Hello, " + $world)""" // quasi-unquote the string to append here...

How can I get all (non-final) object vals and subobject vals using reflection in Scala?

Note: This question is not a duplicate of How can I get all object vals and subobject vals using reflection in Scala?
The answer provided in that question only works for final members.
For example:
scala> object Settings {
| val Host = "host"
| }
defined module Settings
deepMembers(Settings)
res0: Map[String,String] = Map()
It must be a duplicate, but I need a refresher:
$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> object Settings { val Host = "host" ; val Guest = "guest" }
defined object Settings
scala> import reflect.runtime._,universe._
import reflect.runtime._
import universe._
scala> val im = currentMirror reflect Settings
im: reflect.runtime.universe.InstanceMirror = instance mirror for Settings$#c8e4bb0
scala> im.symbol.asClass.typeSignature.members filter (s => s.isTerm && s.asTerm.isAccessor)
res0: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value Guest, value Host)
scala> res0 map (im reflectMethod _.asMethod) map (_.apply())
res2: Iterable[Any] = List(guest, host)
val members = Settings.getClass.getDeclaredFields.map(_.getName).filterNot(_ == "MODULE$")
members: Array[String] = Array(Host)
This works but I think there's certainly a better way of doing this.

Sort a typed Scala HashMap

I searched the answers of sorting a scala HashMap.
Which is
opthash.toSeq.sortBy(_._1)
I just want to sorted by key, thus the above solution should apply.
However, here is my situation that the above solution resulted in an error:
def foo (opthash : HashMap[Int,String]) = {
val int_strin_list = opthash.toSeq.sortBy(_._1);
"return something"
}
I got the following error message:
value sortBy is not a member of Seq[(Int, String)]
Did I miss something? I am pretty sure that sortBy is a member of type Seq...
Any suggestion will be appreciated.
Make sure to use Scala HashMap and not java HashMap. Are you sure you did not misread the error message?
scala> import java.util.HashMap
import java.util.HashMap
scala> def foo (opthash : HashMap[Int,String]) = {
| val int_strin_list = opthash.toSeq.sortBy(_._1);
| "return something"
| }
<console>:13: error: value toSeq is not a member of java.util.HashMap[Int,String]
val int_strin_list = opthash.toSeq.sortBy(_._1);
^
The right way to go is:
scala> import scala.collection.immutable.HashMap
import scala.collection.immutable.HashMap
scala> def foo (opthash : HashMap[Int,String]) = {
| val int_strin_list = opthash.toSeq.sortBy(_._1);
| "return something"
| }
foo: (opthash: scala.collection.immutable.HashMap[Int,String])String
Or too use the mutable HashMap if that is the case.

Problem with outputting map values in scala

I have the following code snippet:
val map = new LinkedHashMap[String,String]
map.put("City","Dallas")
println(map.get("City"))
This outputs Some(Dallas) instead of just Dallas. Whats the problem with my code ?
Thank You
Use the apply method, it returns directly the String and throws a NoSuchElementException if the key is not found:
scala> import scala.collection.mutable.LinkedHashMap
import scala.collection.mutable.LinkedHashMap
scala> val map = new LinkedHashMap[String,String]
map: scala.collection.mutable.LinkedHashMap[String,String] = Map()
scala> map.put("City","Dallas")
res2: Option[String] = None
scala> map("City")
res3: String = Dallas
It's not really a problem.
While Java's Map version uses null to indicate that a key don't have an associated value, Scala's Map[A,B].get returns a Options[B], which can be Some[B] or None, and None plays a similar role to java's null.
REPL session showing why this is useful:
scala> map.get("State")
res6: Option[String] = None
scala> map.get("State").getOrElse("Texas")
res7: String = Texas
Or the not recommended but simple get:
scala> map.get("City").get
res8: String = Dallas
scala> map.get("State").get
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:262)
Check the Option documentation for more goodies.
There are two more ways you can handle Option results.
You can pattern match them:
scala> map.get("City") match {
| case Some(value) => println(value)
| case _ => println("found nothing")
| }
Dallas
Or there is another neat approach that appears somewhere in Programming in Scala. Use foreach to process the result. If a result is of type Some, then it will be used. Otherwise (if it's None), nothing happens:
scala> map.get("City").foreach(println)
Dallas
scala> map.get("Town").foreach(println)