Here is my problem:
trait Caller {
type EntityType
def parseEntity(entity: String): EntityType
}
trait IntCaller extends Caller {
implicit def strToInt(s: String) = s.toInt
override type EntityType = Int
override def parseEntity(entity: String): EntityType = entity
}
trait DoubleCaller extends Caller {
implicit def strToDouble(s: String) = s.toDouble
override type EntityType = Double
override def parseEntity(entity: String): EntityType = entity
}
object main {
def main(args: Array[String]): Unit = {
val intCaller = new IntCaller{}
val doubleCaller = new DoubleCaller{}
println("Result is: " + intCaller.parseEntity("5"))
println("Result is: " + doubleCaller.parseEntity("5.0"))
}
}
As you can see I keep repeating the code for: parseEntity
method. If I wanted to add a FloatCaller
I would have to rewrite parseEntity
even though its implementation would be the same.
How can I write the implentation of the parseEntity in the Caller
, so that I don't have to write the same code in the child traits again and again?
Disclaimer:
This is a simplification of a real problem I have with SprayJsonSupport
from akka.http.scaladsl.marshallers.sprayjson
.
You would be better off using a factory method that can build instances of a Caller
given a conversion function. The only thing that's different between IntCaller
and DoubleCaller
is toInt
and toDouble
(and the types, of course).
trait Caller {
type EntityType
def parseEntity(entity: String): EntityType
}
object Caller {
def apply[A](f: String => A): Caller = new Caller {
type EntityType = A
def parseEntity(entity: String): EntityType = f(entity)
}
}
scala> val IntCaller = Caller(_.toInt)
scala> IntCaller.parseEntity("123")
res1: IntCaller.EntityType = 123
scala> val DoubleCaller = Caller(_.toDouble)
scala> DoubleCaller.parseEntity("1.23")
res2: DoubleCaller.EntityType = 1.23
If you want to keep using inheritance, then continue to force the sub-classes or traits to implement the conversion with parseEntity
. It's not really necessary to using implicit conversions, though. The only reason it appears that there is repeated code is because the implicit conversion makes parseEntity
look the same for each implementation, even though it's really not (because it needs to resolve a different implicit).
trait Caller {
type EntityType
def parseEntity(entity: String): EntityType
}
trait IntCaller {
type EntityType = Int
def parseEntity(entity: String): EntityType = entity.toInt
}