vendredi 3 avril 2015

How to make a parameterized trait which can instantiate classes?

I am using the "case class instead of Enumeration" pattern, and want to have a list of all values per "enumeration" as well as a few methods. So I decided to not just derive my case classes from a sealed abstract class, but to derive all the sealed abstract classes from a superclass called Lookup, and to define a LookupTrait from which to derive the abstract classes' companion objects.



abstract class Lookup {
val name: String
override def toString = name
}

trait LookupTrait[T<:Lookup] {
val all: Map[String, T]
val default: T
def withName(name: String): T =
if(all.contains(name)) all(name)
else default
}


And an example lookup looks like this:



sealed case class StudyGoal(override val name: String) extends Lookup

object StudyGoal extends LookupTrait[StudyGoal] {

override val all = Map(
"present new evaluation method" -> StudyGoal("present new evaluation method"),
"evaluate existing product" -> StudyGoal("evaluate existing product"),
"develop new theoretical model" -> StudyGoal("develop new theoretical model"),
"unknown" -> StudyGoal("unknown")
)
override val default = StudyGoal("unknown")
}


I would prefer to simply define a list of strings in the companion object of each lookup and have the trait instantiate the case classes. But while I found three different ways of doing reflection in Scala - using a Manifest, a TypeTag, and getting the constructor of a class as described in the documentation, all of them seem to require to have an instance of the class present, and I couldn't get them to work within the parameterized LookupTrait trait.


I would like to have something like:



abstract class Lookup {
val name: String
override def toString = name
}

trait LookupTrait[T<:Lookup] {
val allNames: List[String]

val default: T = //Instantiate a T using the string "unknown".
//It is OK that this string will be the same for all Lookups.

val all: Map[String, T] = allNames.map(
n => n -> //instantiate a T here, using n as the parameter
) += default

def withName(name: String): T =
if(all.contains(name)) all(name)
else default
}

sealed case class StudyGoal(override val name: String) extends Lookup

object StudyGoal extends LookupTrait[StudyGoal] {

override val allNames = List(
"present new evaluation method"),
"evaluate existing product",
"develop new theoretical model"
)
}





Aucun commentaire:

Enregistrer un commentaire