Similarly named abstract types must conform when mixed together:
scala> trait Foo { type T }
defined trait Foo
scala> trait Bar { type T }
defined trait Bar
scala> trait FooBar { this: Foo with Bar => }
defined trait FooBar
scala> trait FooImpl extends Foo { type T = Int }
defined trait FooImpl
scala> trait BarImpl extends Bar { type T = Double }
defined trait BarImpl
scala> trait FooBarImpl extends FooBar with FooImpl with BarImpl
<console>:12: error: trait FooBarImpl inherits conflicting members:
type T in trait FooImpl, which equals Int and
type T in trait BarImpl, which equals Double
(Note: this can be resolved by declaring an override in trait FooBarImpl.)
trait FooBarImpl extends FooBar with FooImpl with BarImpl
trait AddComponent {
type T
def addition: Add
trait Add {
def constant: T
def plus( t1: T, t2: T ): T
def add( t: T ) = plus( t, constant )
}
}
trait MulComponent {
type T
def multiplication: Mul
trait Mul {
def constant: T
def times( t1: T, t2: T ): T
def mul( t: T ) = times( t, constant )
}
}
trait OperationsComponent { this: AddComponent with MulComponent =>
def operations: Operations
trait Operations {
def neg( t: T ): T
}
}
Here, it is ensured that T of Add and Mul are compatible, and that is all that the Operations trait really cares about.