Can anyone explain this strange behavior with my case class?
case class Dai(var g :Int) {
def getG() = g
}
val dai: Dai = Dai(20)
dai.g = 30
// why v2 difference with getGet
val v2 = dai.getG // 30
var getGet = dai.getG // 20
Intellij Worksheet has this problem
But not from the REPL
Must have something to do with how Intellij is running the worksheet?
It doesn't happen on my system running 2.11.2. Most probably a bug that can be fixed by upgrading your distribution.
scala> case class Dai(var g :Int) {
| def getG() = g
| }
defined class Dai
scala>
scala> val dai: Dai = Dai(20)
dai: Dai = Dai(20)
scala>
scala> dai.g = 30
dai.g: Int = 30
scala> // why v2 difference with getGet
scala> val v2 = dai.getG // 30
v2: Int = 30
scala> var getGet = dai.getG // 20
getGet: Int = 30
Related
I know that one can define an operator in Scala like this :
class value(var valu:Int) {
def +(i:Int) = { this.valu + i }
def ==>(i:Int ) = { this.valu = i }
}
But I cannot seem to overload the = operator like this :
class value(var valu:Int) {
def =(i:Int) = { this.valu = i }
}
Do you know if there is any way to do this?
The syntax for making mutable objects isn't obvious and isn't encountered often because mutability is generally undesirable.
class Value(private var valu:Int) {
def update(i:Int) :Unit = valu = i
}
val v = new Value(19)
v() = 52
= is a reserved word like yield, so to use it as an identifier, you put it in backticks, though I suspect no one does that:
scala> class C(var i: Int) { def `=`(n: Int) = i = n }
defined class C
scala> val c = new C(42)
c: C = C#9efcd90
scala> c.`=`(27)
scala> c.i
res1: Int = 27
scala> c `=` 5
scala> c.i
res3: Int = 5
Compare:
scala> val yield = 2
^
error: illegal start of simple pattern
scala> val `yield` = 2
yield: Int = 2
this is what i want:
scala> var x:Int = 10
x: Int = 10
scala> var y:Int = 20
y: Int = 20
scala> val ret = q"return $x>$y"
ret: universe.Return = return 10.$greater(20)
scala> val result1 = toolbox.compile(ret)()
result1: Any = false
But the problem is that I will be getting the expression $x>$y in a string var, like
scala> m
res20: String = $x>$y
And then I want to perform the operation as,
var ret = q"return $m"
but this return:
scala> var ret = q"return $m"
ret: universe.Return = return "$x>$y"
which is not serving the purpose. How can I get the value of x and y in the last step instead $x and $y.
You can mix quasiquotes and ToolBox.parse to achieve results mostly like what you are looking for:
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.universe._
val toolbox = scala.reflect.runtime.currentMirror.mkToolBox()
val s = "10>20"
val ret = q"return ${toolbox.parse(s)}"
// reflect.runtime.universe.Return = return 10.$greater(20)
toolbox.eval(ret)
// Any = false
Making use of your values as variables:
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.universe._
val toolbox = scala.reflect.runtime.currentMirror.mkToolBox()
val x = 10
val y = 20
val m = "x>y"
val ret = q"return ${toolbox.parse(m)}"
// reflect.runtime.universe.Return = return x.$greater(y)
If you evaluate q"return ${toolbox.parse(m)}" you will see the error because x and y are not in scope.
scala> toolbox.eval(q"return ${toolbox.parse(m)}")
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
object > is not a member of package x ...
To fix that:
import scala.tools.reflect.ToolBox
import scala.reflect.runtime.universe._
val toolbox = scala.reflect.runtime.currentMirror.mkToolBox()
val q1 = q"val x = 10; val y = 20; "
val m = "x>y"
val ret = q"""
| ..$q1
| return ${toolbox.parse(m)}
| """
toolbox.eval(ret)
// Any = false
I can use apply in Scala to overload the () operator.
class A {
val arr = Array[Int](1,2,3,4,5)
def apply(i:Int) = {
arr(i)
}
}
object Main extends App {
val a = new A
println(a(0))
}
When I set the value, I can add the set method
def set(i:Int, value:Int) = {arr(i) = value}
...
arr.set(3, 10)
Does Scala allow better syntactic sugar such as arr(3) = 10 to get the same results?
You could define the update method:
scala> class A {
| val arr = Array[Int](1,2,3,4,5)
| def apply(i: Int) = {
| arr(i)
| }
| def update(i: Int, x: Int) {
| arr(i) = x
| }
| }
defined class A
scala> val a = new A
a: A = A#7d117aef
scala> a(0)
res0: Int = 1
scala> a(0) = 42
scala> a(0)
res2: Int = 42
I'd like to dynamically execute the methods that start with removeAt of the object X at runtime.
How can I do that with the scala.reflect.runtime.universe API described in REFLECTION Environment, Universes, and Mirrors
Here is solution for your problem:
object X {
def aa = 1
def ab = 2
def removeAtX = 3
def bb = 4
def removeAtY = 5
}
val ru = scala.reflect.runtime.universe
val m = ru.runtimeMirror(getClass.getClassLoader)
val im = m.reflect(X)
val l = X.getClass.getMethods.map(_.getName).filter(_ startsWith "removeAt")
val r = l.map(y => ru.typeOf[X.type].declaration(ru.newTermName(y)).asMethod).map(im.reflectMethod(_).apply())
Result:
r: scala.collection.mutable.ArraySeq[Any] = ArraySeq(3, 5)
I'm using Scala 2.10.1 and I'm trying the define a method which will retrieve all the vals (including the inherited ones) from an object.
I have the following:
import scala.reflect.runtime.{universe => ru}
object Reflection {
val mirror = ru.runtimeMirror(this.getClass.getClassLoader)
def findVals(x: Any): Iterable[String] = {
val theType = mirror.classSymbol(x.getClass).toType
theType.members.collect({case x if x.isTerm => x.asTerm}).filter(_.isVal).map(_.name.toString)
}
}
I am testing on these two classes:
class Base {
val x = 10
}
class Child extends Base {
val y = 20
}
When calling the following code:
val x = new Child
val vs = Reflection.findVals(x)
println(vs)
The result is List(y)
For some reason, the isVal method returns false for the term corresponding to the x field from the Base class.
Can someone tell me what's the problem here? Am I doing something wrong?
Per Why don't Scala case class fields reflect as public? you should use isAccessor instead of isVal.
I'm actually using isGetter and setter to properly filter vars per your comment:
def findVals(x: Any): Iterable[String] = {
val theType = mirror.classSymbol(x.getClass).toType
val xtm = theType.members.collect({case x if x.isTerm => x.asTerm})
xtm.filter(m => m.isGetter && !xtm.exists(m.setter == _)).map(_.name.toString)
}
Results:
scala> class Base {
| var x = 10
| val xx = 2
| }
defined class Base
scala> class Child extends Base {
| val y = 3
| }
defined class Child
scala> val x = new Child
x: Child = Child#1c0026e
scala> val vs = Reflection.findVals(x)
vs: Iterable[String] = List(y, xx)
scala> println(vs)
List(y, xx)
Using SMirror:
scala> implicit val mirror = scala.reflect.runtime.currentMirror
mirror: reflect.runtime.universe.Mirror = JavaMirror with scala.tool…
scala> import net.fwbrasil.smirror._
import net.fwbrasil.smirror._
scala> class Base {
val x = 10
}
defined class Base
scala> class Child extends Base {
val y = 20
}
defined class Child
scala> val x = new Child
x: Child = Child#448593d0
scala> x.reflect.vals
res5: List[net.fwbrasil.smirror.SInstanceVal[Child]] = List(val x: scala.Int (bound to Child#448593d0), val y: scala.Int (bound to Child#448593d0))
scala> x.reflect.vals.head.get
res7: Any = 10
So, this is terribly inelegant, but it seems to work:
import scala.reflect.runtime.{universe => ru}
object Reflection {
val mirror = ru.runtimeMirror(this.getClass.getClassLoader)
val ObjectClass = classOf[java.lang.Object];
def findVals(x: Any) : Iterable[String] = findVals( x.getClass, List.empty );
def findVals(clz: Class[_], accum : Iterable[String]): Iterable[String] = {
clz match {
case ObjectClass => accum;
case _ => {
val theType = mirror.classSymbol(clz).toType
val newVals = theType.members.collect({case x if x.isTerm => x.asTerm}).filter(_.isVal).map(_.name.toString)
findVals( clz.getSuperclass, accum ++ newVals )
}
}
}
}
Then...
scala> class Base {
| val x = 10
| var z = 20
| }
defined class Base
scala> class Child extends Base {
| val y = 20
| var a = 9
| }
defined class Child
scala> val x = new Child
x: Child = Child#3093266d
scala> val vs = Reflection.findVals(x)
vs: Iterable[String] = List("y ", "x ")
scala> println(vs)
List(y , x )
It seems that, at least for now, Scala reflection looks at the Java field to determine the presence of a val, so I guess you just have to climb the class hierarchy... I'm guessing it looks for the presence of a setter to distinguish val from var. Again, not so lovely, but functional.