1

I have a very specific scenario, in which I have some different abstract classes the have child case classes that can have different parameters, for example:

abstract class ball() {}

case class football(_name: String, _shape: String) extends ball

case class basketball(_name: String, _size: Int) extends ball

and a different abstract class:

abstract class food() {}

case class vegetarian(_name: String, calories: Int) extends food

case class meat(_name: String, proteinCount: Int) extends food

Now, the problem I'm facing is that I need to somehow extract the name of all of those without knowing what class it is, I just know that ALWAYS, EACH CLASS has a parameters named _name.

Supposing we have an object of any of above classes, I'm trying to do it like this:

object.getClass.getDeclaredField("_name").get(this)

But I'm getting the error:

can not access a member of class package.food with modifiers "private"

I tried putting val and var before parameters in class but it doesnt help. I also tried doing "setAccessible(true)" in a line before get(this), which also doesn't help.

Sheenah
  • 85
  • 12

1 Answers1

1

The obvious clean solution would be to have a least a common trait to all these classes:

trait HasName {
  def _name: String
}

and then you can safely do obj.asInstanceOf[HasName]._name. Better yet if you manage to keep around the static information that obj is a HasName, in which case obj._name suffices.

If you can't do any of that, reflection is the way to go. You can do it pretty easily using a structural type, in this case:

obj.asInstanceOf[{ def _name: String }]._name

Note that this will be slower than the above HasName solution, and completely unchecked at compile time.

sjrd
  • 21,805
  • 2
  • 61
  • 91
  • Could you please explain exactly how the second solution works? I copied it and it worked in my project, but I don't understand it fully. Thanks a lot. – Sheenah May 15 '15 at 12:26
  • Also, how to implement a similar solution to the method of the same name? – Sheenah May 15 '15 at 12:31
  • The scalac compiler implements calls to methods of structural types using Java reflection (at least, on the JVM). Something like `obj.getClass.getMethod("_name", classOf[String]).invoke(obj)`, to give a simplified idea. – sjrd May 15 '15 at 14:11