Reputation: 1365
I'm very new to Scala so forgive me if this is a real easy question but I could not find anything to help me or I could not figure out the right search terms. How can I make this work?
scala> trait Foo
defined trait Foo
scala> class FooImpl extends Foo
defined class FooImpl
scala> trait Bar { def someMethod(foo: Foo) }
defined trait Bar
scala> class BarImpl extends Bar { def someMethod(foo: FooImpl) {} }
<console>:10: error: class BarImpl needs to be abstract, since method someMethod in trait Bar of type (foo: Foo)Unit is not defined
(Note that Foo does not match FooImpl)
class BarImpl extends Bar { def someMethod(foo: FooImpl) {} }
Why doesn't FooImpl match Foo since Foo is a trait? I'm guessing I need to alter the signature of someMethod in Bar to say that I'm expecting something that extends Foo or "with Foo" but I can't seem to find documentation for this.
Upvotes: 3
Views: 4926
Reputation: 740
Jens Schauder's answer works but forces you to define the type in the trait signature. Instead, you can do the same on the method level:
scala> trait Foo
defined trait Foo
scala> class FooImple extends Foo
defined class FooImple
scala> trait Bar { def methodA[T <: Foo](foo: T) }
defined trait Bar
scala> class BarImpl extends Bar { def methodA[FooImpl](foo: FooImpl){} }
defined class BarImpl
Upvotes: 0
Reputation: 81882
dhg explained why this doesn't work and why you probably don't really want it.
But if you still want it, you can do it like this:
trait Foo
class FooImpl extends Foo
trait Bar[F <: Foo] { def someMethod(foo: F) }
class BarImpl extends Bar[FooImpl] {
def someMethod(foo: FooImpl) {}
}
Upvotes: 4
Reputation: 52681
The problem is that the Bar
trait's someMethod
declaration specifies that any kind of Foo
can be passed as an argument. You can think of this as its "contract". The contract says that any implementation of Bar
will have a method someMethod
that will accept any kind of Foo
.
Your BarImpl
class is an implementation of Bar
and has a someMethod
implementation. Unfortunately, its implementation of someMethod
only accepts FooImpl
kinds of Foo
objects: not any kind of Foo
. Since it doesn't allow you to pass in Foo
objects that aren't FooImpl
objects, it violates the contract specified by the trait definition. Implementations can't be more restrictive than the contract specifies.
As an example:
class FooImplB extends Foo
val bar: Bar = new BarImpl
val foo: Foo = new FooImplB
bar.someMethod(foo)
Here we declare a Bar
called bar
and a Foo
called foo
. According to the definition of Foo
I should be able to pass foo
into bar.someMethod
. Except that BarImpl.someMethod
only accepts FooImpl
kinds of Foo
s and not FooImplB
s! So we have a problem.
Upvotes: 6