Kamran Kamran - 3 months ago 11
Scala Question

Scala Generic, specify generic through variable

I have a class which takes a generic as such:

class MyClass[T <: RecordType] (myRecordType: T) {
def doAction() : Unit =
{
myRecordType.someMethod();
}
}


I have a series of subclasses of RecordType that all implement someMethod(). Currently, i call each one individually in my main class as follows:

def main(args: Array[String]): Unit =
{
new MyClass[RecordType10](new RecordType10()).doAction();
new MyClass[RecordType20](new RecordType20()).doAction();
new MyClass[RecordType30](new RecordType30()).doAction();
// many more record types each repeated
}


Ideally, instead of adding a new line for every record type, we would love to have an enumeration of valid record types and just loop through. This way, adding new record types would be as simple as adding to the pre-defined list. But I cannot figure out how to have an Array or Enumeration of class types and then pass those to the instantiation of MyClass. For example, this simple test:

val testClass = classOf(RecordType10);
new MyClass[testClass](new testClass()).doAction();


... it does not compile.

So basic question is: is there a way to have a collection of classes and then iterate through that collection and instantiate another class passing the value for the generic type. Something like this:

val myClasses = Array(classOf(Record10), classOf(Record20), classOf(Record30));
for (theClass <- myClasses)
{
new MyClass[theClass](new theClass()).doAction();
}


Looking forward to any response. Thanks!

Answer

Using OP's example for simplicity:

object Main {
  trait RecordType {
    def someMethod()
  }

  class MyClass[T <: RecordType](myRecordType: T) {
    def doAction(): Unit = myRecordType.someMethod()
  }

  class RecordType10() extends RecordType {
    override def someMethod(): Unit = println("some method 10")
  }

  class RecordType20() extends RecordType {
    override def someMethod(): Unit = println("some method 20")
  }

  def main(args: Array[String]): Unit = {
    new MyClass[RecordType10](new RecordType10()).doAction()
    new MyClass[RecordType20](new RecordType20()).doAction()

    val myClasses = List(classOf[RecordType10], classOf[RecordType20])
    for(theClass <- myClasses) {
      val instance = theClass.newInstance()
      val m = new MyClass(instance)
      m.doAction()
    }
  }
}