var in the scala class automatically gets getters and setters, which you can see through scala reflection through members
import scala.reflect.runtime.{universe => ru} class A(var x: Int) scala> ru.typeOf[A].members.filter{_.name.toString.contains("x")} res22: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(variable x, method x_=, method x)
However, if you create a subclass that reuses the var name in the constructor, getter will not:
class B(x:Int, var y: Int) extends A(x) scala> ru.typeOf[B].members.filter{_.name.toString.contains("x")} res23: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value x, method x_=) scala> res23.head.asTerm.isVal res25: Boolean = true
This seems a bit wrong ... because B still has a getter for x (and its not a val )
scala> val b = new B(5,6) b: B = B@270288ed scala> bx res26: Int = 5 scala> bx = 7 bx: Int = 7 scala> bx res27: Int = 7
If I try to pretend that the value x I got from members is getter, I get an error:
scala> val xGetter = res23.head.asTerm xGetter: reflect.runtime.universe.TermSymbol = value x scala> val objMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(b) objMirror: reflect.runtime.universe.InstanceMirror = instance mirror for B@270288ed scala> val getterMirror = objMirror.reflectField(xGetter) scala.ScalaReflectionException: Scala field x isn't represented as a Java field, neither it has a Java accessor method note that private parameters of class constructors don't get mapped onto fields and/or accessors, unless they are used outside of their declaring constructors.
What is the right workaround here? Is it wrong to have a subclass name, its args constructor matches the names in the parent arguments? Or instead of calling members , do I need to work on all superclasses to get all getters and setters?
Note that members gives me an inherited getter until a subclass creates a constructor with the same name:
class Y(var x: Int) class Z(q:Int, z: Int) extends Y(q) scala> ru.typeOf[Z].members.filter{_.name.toString.contains("x")} res28: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(method x_=, method x)
EDIT If it is unclear, I really ask: 1) is this an error in scala reflection? 2) if not, I should: (a) never have classes that use constructor field names the same as field names in base classes? (if so, I'm probably defining all my classes incorrectly ...) or (b) getting all getters and setters, should I just look at the list of all the parent classes and use declarations , instead of relying on members to do the right thing because it does not work in this case
EDIT 2 in response to @ som-snytt's answer, the visible methods of x really are on x in A , and not in the parameter in constructor B For instance:.
class A(var x: Int){def showMeX {println(x)}} class B(x:Int, var y: Int) extends A(x) scala> val b = new B(5,10) scala> b.showMeX 5 scala> bx = 17 bx: Int = 17 scala> b.showMeX 17
so I donβt think that either the getter or setter for x been obscured in terms of normal user code. It was only shaded for the reflection code ... and it makes no sense to me that there will be two different versions of the shading.