Tom Tom - 1 month ago 8
Scala Question

TermSymbol.isVal doesn't look correct

I have following code to check whether

x
in class A is val or var

import scala.reflect.runtime.universe._
class A {
val x = 10
}

val y: Symbol = typeOf[A].member(TermName("x"))
println(y.asTerm.isVal + "," + y.asTerm.isVar)
println()


The output is:

false,false


x
is declared as val, I would ask why
y.asTerm.isVal
is evaluated as false

Answer Source

You can get a hint if you do this:

typeOf[A].decls // List everything inside A
SynchronizedOps(constructor A, value x, value x)

There are two value xs, because x exists in two forms. Remember Scala's Uniform Access Principle: public vals are never truly public. Instead, they are a private[this] val combined with a generated getter def. One value x in the list is the private[this] val x, and the other is the def x = x (invalid Scala, but that's how it is). You can define the class with -Xprint:typer to see it.

typeOf[A].member(TermName("x")), then, returns the public def x instead of returning the private[this] val x. You can do (from least to most specific) y.asTerm.isMethod/.isAccessor/.isGetter to verify this.

If you just need to get the setter for the field, you can call y.asTerm.setter, which will return def x_= if x is a var, and will return NoSymbol if there isn't a setter. If you need the field itself, you can call y.asTerm.accessed.asTerm, which is actually a val: y.asTerm.accessed.asTerm.isVal.