I have an abstract class :
abstract class Foo(...){
def bar1(f : Foo) : Boolean
def bar2(f : Foo) : Foo
}
multiple classes extend Foo and override the methods
class FooImpl(...) extends Foo{
override def bar1(f : Foo) : Boolean {
...
}
override def bar2(f : Foo) : Foo {
...
}
}
Is it possible, using generics (or something) to make the overriding methods have the parametertype of the subclass implementing it? Like this :
class FooImpl(...) extends Foo{
override def bar1(f : FooImpl) : Boolean {
...
}
override def bar2(f : FooImpl) : FooImpl {
...
}
}
I was thinking something along the line of the following, but that didn't seem to work...
abstract class Foo(...){
def bar1[T <: Foo](f : T) : Boolean
def bar2[T <: Foo](f : T) : T
}
class FooImpl(...) extends Foo{
override def bar1[FooImpl](f : FooImpl) : Boolean {
...
}
override def bar2[FooImpl](f : FooImpl) : FooImpl{
...
}
}
Any help is much appreciated!
Thank you.
T
needs to be a type parameter on theFoo
class that you inherit from, not on the methods themselves.Different subclasses of
Foo
don't actually have a common supertype in this version of the code, because they extend from different parameterizations ofFoo
. You can use parameterized methods that refer toFoo[T]
when you need to work with the common supertype, but I tend to prefer the abstract type solution I posted in my other answer, becuase it doesn't leak the details of the generics to all of the other functions that have to deal with Foos.To make Ken Blum's second version a little bit nicer you can use self types:
Ideally you combine things mentioned above, i.e.
"[T <: Foo[T]]" means T is subclass of Foo[T], AND "self:T =>" means that Foo[T] is subclass of T, and together it is a little weird way to tell that Foo[T] is exactly same as T.
Only with that I could make following code compile and work as intended:
In this version, different subclasses of
Foo
all shareFoo
as a superclass, but to hold the return value ofbar2
(or the parameters tobar1
orbar2
) in a setting where all you know about your object (let's say it's namedobj
) is that it's aFoo
, you need to use the typeobj.T
as the type of the variable.You can parameterize
Foo
to accomplish some of the effect easily:If you want to rule out the second case, there's no straightforward way to do it with the current features in Scala.
Also, some of what you seem to want doesn't make sense if you give an actual implementation in
Foo
. IfFoo
promises to take anyFoo
but you give it a method that insists on only aFood
, it will break if you you pass it a different subclass ofFoo
(e.g.Fool
). So the compiler won't let you do that.