Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala: Retrieve arguments used to construct class instance in an inheritable way?

in scala, i have a situation where a base class/trait is extended by very many child classes. i'm going to be serializing an instance of a child class (for the purpose of reconstructing it later) by getting the name of the class and the arguments used to instantiate the class. it's easy to get the name of the class instance using reflection but i'm not sure how to get the arguments of the instance in a way that doesn't require me to write code in every child class. this needs to also work for arguments called by name. it seems tricky because every child class might have a completely different number and type of constructor arguments:

abstract class Base {
  // ideally implements some way of finding out the arguments used to construct this object
  def getArgs = {...}
}

class ChildA() // args would be a 0-tuple

class ChildB(arg1: Int) // getArgs would be a 1-tuple of arg1

class ChildC(arg1: Double, arg2: Boolean) // args would be a 2-tuple of (arg1, arg2)

// etc... 

what i want to avoid is having each class implementing a method like "getArgs" and just returning a tuple duplicating the arguments from the constructor. any way to do this?

i realize an alternative approach is to have some sort of interceptor for object creation, but i couldn't figure out how to do that without having to write boilerplate code for every child class as well.

edit: the case class approach is elegant but in my situation is not suitable because we must be able to allow concrete child classes to extend other concrete child classes.

like image 998
Heinrich Schmetterling Avatar asked May 19 '11 08:05

Heinrich Schmetterling


1 Answers

If your goal is to avoid writing code in each child class to capture the arguments and all child classes are in a flat hierarchy, directly inheriting from Base and not from each other, you should consider declaring them as case classes instead. They would then automatically extend Product and you could use and productIterator to e.g. save all args to an Array[Any] (I'm using Array because that's what's needed when you reflectively call the constructor of these classes later):

scala> def toArray(p: Product) = p.productIterator.toArray
toArray: (p: Product)Array[Any]

scala> case class ChildA()
defined class ChildA

scala> toArray(ChildA())
res0: Array[Any] = Array()

scala> case class ChildB(arg1: Int)
defined class ChildB

scala> toArray(ChildB(42))
res1: Array[Any] = Array(42)

If you want toArray to only accept subclasses of Base, then declare its parameter as Product with Base.

like image 190
Jean-Philippe Pellet Avatar answered Nov 08 '22 03:11

Jean-Philippe Pellet