I am trying to understand and incorporate upper bound types with overriding in my system, but have not been able to achieve it without some ugly code. I have the following 2 traits:
trait MyId {
def getType: Int // For simplicity. This is Enum/Object in code.
def id: Any
}
trait MyTrait {
protected def supportedType: Int
def doSomething(id: MyId): Unit = {
if (id.getType == myType)
doSomethingInternal(id)
}
protected def doSomethingInternal(id: _ <: MyId): Unit
}
and I want to create subtypes as:
class X(x: Long) extends MyId {
override def getType: Int = 1
override def id: Long = x
}
class Y(y: String) extends MyId {
override def getType: Int = 2
override def id: String = y
}
class A extends MyTrait {
override protected def supportedType: Int = 1
override protected def doSomethingInternal(id: X): Unit {...}
}
class B extends MyTrait {
override protected def supportedType: Int = 2
override protected def doSomethingInternal(id: Y): Unit {...}
}
However, this does not work. The workaround I have been using is to use asInstanceOf[]
:
class A extends MyTrait {
override protected def supportedType: Int = 1
override protected def doSomethingInternal(id: MyId): Unit {
val id2 = id.asInstanceOf[X]
}
}
class B extends MyTrait {
override protected def supportedType: Int = 2
override protected def doSomethingInternal(id: MyId): Unit {
val id2 = id.asInstanceOf[Y]
}
}
Is there a way I can get rid of the asInstanceOf[]
?
EDIT
Further more, I have the following processor which requires calling the correct MyTrait
subclass based on the given MyId.getType
:
def process(ids: Seq[MyId], processors: Map[Int, MyTrait]): Unit = {
ids.foreach{ id =>
processors.get(id.getType).doSomething(id)
}
}
Edit 2:
getType
isInt
for simplicity here. This is actually an enum/object in my code.- Renamed
getSomething
todoSomething
for more clarity.
It's not clear from the question if there's a specific need for the indirection between
getSomething
andgetSomethingInternal
other than thegetType
consistency check, but since it looks like the goal is just to prevent callinggetSomething
with the wrong id type, it seems to me it'd be simpler to define MyTrait with a type parameter for the expected id:Then things look like this: