I want to achieve the following:
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[T <: Super] {
def test = T.typeSpecific
}
val testerA = new Tester[SubA]
val testerB = new Tester[SubB]
testerA.test // should return 1
testerB.test // should return 2
Is something like this possible in Scala? This fails because the value of T
is not found in Tester.test
.
typeSpecific
is not a static member, it belongs to instances of SubA
and SubB
, which you don't have. You also can't statically access anything from a type parameter (it's a type, not an object).
This won't work as is, because you don't have instances of SubA
and SubB
, nor can you obtain them via new Tester[SubA]
. But you can require that Tester
mixes in a type of Super
in order to make it one (and thus have typeSpecific
). This would require you change Super
, SubA
, and SubB
to traits, and would also make your instance anonymous classes.
trait Super {
def typeSpecific: Int
}
trait SubA extends Super {
def typeSpecific = 1
}
trait SubB extends Super {
def typeSpecific = 2
}
// The self-type `this: A =>` requires the mix-in.
class Tester[A <: Super] { this: A =>
def test = typeSpecific
}
val testerA = new Tester[SubA] with SubA
val testerB = new Tester[SubB] with SubB
scala> testerA.test
res2: Int = 1
scala> testerB.test
res3: Int = 2
You could also require A <: Super
as a constructor parameter for Tester
, which is probably the cleaner option.
abstract class Super {
def typeSpecific: Int
}
class SubA extends Super {
def typeSpecific = 1
}
class SubB extends Super {
def typeSpecific = 2
}
class Tester[A <: Super](s: A) {
def test = s.typeSpecific
}
val testerA = new Tester(new SubA)
val testerB = new Tester(new SubB)
scala> testerA.test
res5: Int = 1
scala> testerB.test
res6: Int = 2
Any way you cut it, you're going to need an instance of SubA
or SubB
.