Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't Scala case class fields reflect as public?

Tags:

scala

I've always understood the constructor arguments of case classes as defining public vals.

However, when I reflect the fields, the isPublic method comes up false. Any ideas why?

scala> class Test( val name : String, val num : Int )
defined class Test

scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._

scala> val tpe = typeOf[Test]
tpe: reflect.runtime.universe.Type = Test

scala> def checkValVisibility( t : Type ) = {
     | t.members
     |   .filter( _.isTerm )
     |   .map( _.asTerm )
     |   .filter( _.isVal )
     |   .map( memb => "Val " + memb.name.toString.trim + " is public? " + memb.isPublic )
     |   .mkString("\n")
     | }
checkValVisibility: (t: reflect.runtime.universe.Type)String

scala> checkValVisibility( tpe )
res2: String = 
Val num is public? false
Val name is public? false
like image 997
Steve Waldman Avatar asked Mar 31 '13 13:03

Steve Waldman


1 Answers

The reason is that the actual values that you queried for num and name are indeed private. For case classes (and classes with public class parameters), class parameters are implemented as private fields with public accessors (which are generated automatically for you).

If you want to use Scala Reflection to obtain a symbol representing the public accessor for a given field, you can simply do:

scala> tpe.member("name": TermName)
res02: reflect.runtime.universe.Symbol = value name

You can see that it's a public accessor if you do:

scala> tpe.member("name": TermName).isPublic
res03: Boolean = true

scala> tpe.member("name": TermName).isMethod
res04: Boolean = true

In your case, you filtered out the accessors, leaving only the actual (private) fields. You can change your code from above to achieve what you want by instead checking with isAccessor (or isGetter) instead of isVal.

scala> def checkValVisibility( t : Type ) = {
     |   t.members
     |    .filter( _.isTerm )
     |    .map( _.asTerm )
     |    .filter( _.isAccessor )
     |    .map( memb => "Val " + memb.name.toString.trim + " is public? " + memb.isPublic )
     |    .mkString("\n")
     | }
checkValVisibility: (t: reflect.runtime.universe.Type)String

scala> checkValVisibility(tpe)
res05: String = 
Val num is public? true
Val name is public? true
like image 70
Heather Miller Avatar answered Sep 28 '22 08:09

Heather Miller