I would like to have a method which returns a class of a certain type, but I want the method to behave differently depending on whether or not the class extends a particular trait as follows:
case class ClassA extends TraitA
case class ClassB extends TraitB
case class ClassC extends TraitA
...
def myfunc[T]():T = {
T match {
case TraitA => // return new T in a particular way
case TraitB => // ditto
}
}
Is this possible, or am I going about it the wrong way?
Thanks
Using if expressions in case statements First, another example of how to match ranges of numbers: i match { case a if 0 to 9 contains a => println("0-9 range: " + a) case b if 10 to 19 contains b => println("10-19 range: " + b) case c if 20 to 29 contains c => println("20-29 range: " + c) case _ => println("Hmmm...") }
“match” is always defined in Scala's root class to make its availability to the all objects. This can contain a sequence of alternatives. Each alternative will start from case keyword. Each case statement includes a pattern and one or more expression which get evaluated if the specified pattern gets matched.
Notes. Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.
It is defined in Scala's root class Any and therefore is available for all objects. The match method takes a number of cases as an argument. Each alternative takes a pattern and one or more expressions that will be performed if the pattern matches. A symbol => is used to separate the pattern from the expressions.
You can't compare types directly, because there isn't anything there to compare (at runtime, due to erasure). You could work on a representation of your class:
trait TraitA { }
trait TraitB { }
class ClassA extends TraitA { }
class ClassB extends TraitB { }
def myFunc[T](clazz: Class[T]) = {
if (classOf[TraitA] isAssignableFrom clazz) println("A")
else if (classOf[TraitB] isAssignableFrom clazz) println("B")
else println("?")
}
scala> myFunc(classOf[ClassA])
A
scala> myFunc(classOf[String])
?
or you can pattern match on instances of the class:
def myFunc2[T](t: T) = t match {
case _: TraitA => println("A")
case _: TraitB => println("B")
case _ => println("?")
}
scala> myFunc2(new ClassA)
A
scala> myFunc2(Some(5))
?
You can also use the first approach in a syntactically less obtrusive way via class manifests:
def myFunc3[T](implicit mf: ClassManifest[T]) = {
val clazz = mf.erasure
if (classOf[TraitA] isAssignableFrom clazz) println("A")
else if (classOf[TraitB] isAssignableFrom clazz) println("B")
else println("?")
}
scala> myFunc3[ClassA]
A
scala> myFunc3[String]
?
and you can choose different sorts of dispatch also if the if/else becomes wieldy:
object MyFunc {
val dispatch = Map(
classOf[TraitA] -> (() => println("A")),
classOf[TraitB] -> (() => println("B"))
)
val default = () => println("?")
def apply[T](implicit mf: ClassManifest[T]) =
dispatch.find(_._1 isAssignableFrom mf.erasure).map(_._2).getOrElse(default)()
}
scala> MyFunc[ClassA]
A
scala> MyFunc[String]
?
Note that any generic code that you use this from will need to have a class manifest available (either as an implicit parameter or in shorthand, [T: ClassManifest]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With