Can I safely inherit both a trait and a base class which share the same method?
Like:
trait MyTrait {
def getValue:String
}
class SomeClass {
def getValue:String = [concrete implementation]
}
then:
class MyClass extends SomeClass with MyTrait
The reason to do this is I'd like to use it in another (abstract) class, which defines the required API only via the MyTrait
trait, and I cannot have SomeClass
inherit this trait directly (because its from another unrelated library).
abstract class AbstractOtherClass {
val mainObject:MyTrait
}
and then the concrete implementation of that class:
class OtherClass extends AbstractOtherClass {
val mainObject:MyTrait = new MyClass
def something = {
println(mainObject.getValue) // shall call SomeClass.getValue
}
}
Solution
After SergGr's suggestion I ended up with a solution like this:
abstract class AbstractOtherClass {
def getValue:String
}
class OtherClass extends AbstractOtherClass {
val mainObject:SomeClass = ...
def getValue:String = mainObject.getValue
}
It looks like there are two different questions here
As long as your trait
has only declaration of the method but no implementation, it works by design. This is one of the unusual but expected usage pattern. If several trait
s or a trait
and a class
have implementations of the same method, there is still an explicitly specified logic of linearization that specifies how to resolve the conflicts but I'd say that in most cases relying on that is a bad design.
The thing you are trying to do looks like an adapter pattern to me and I'd say that from the design point of view it is better to implement it using object composition rather than inheritance:
trait MyTrait {
def getValue:String
}
class SomeClassWrapper(delegate: SomeClass) extends MyTrait {
override def getValue:String = delegate.getValue
}
Doing it this way you don't bind your API to the implementation of the library. For example you can rename the method to getAbcValue
value if this makes more sense in your context. Or if you at some point find another library that does the same work better but that has a different name for such method (like calculateValue
), you have to create just another wrapper class and don't have to change all the getValue
calls to calculateValue
calls.