Rules for mixing same trait several times
I was trying to write some piece of abstract code making it more complicate step by step. And it had broken at one of this steps.
1st step, correct
trait Base
trait C1 extends Base
trait Abst extends Base
trait Conc extends Abst with C1
2nd step, correct
object BaseHolder {
trait Data
}
object C1Holder {
trait Data extends BaseHolder.Data
}
trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data
开发者_如何学编程
3rd step, buggy error
trait BaseHolder {
trait Data
}
object BaseHolder extends BaseHolder
trait C1Holder extends BaseHolder {
trait Data extends super.Data
}
object C1Holder extends C1Holder
trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data
I've got the error: illegal inheritance; trait Con inherits different type instances of trait Data
What does this error means and is there any way to bypass it?
The full error message is
[error] trait Conc inherits different type instances of trait Data:
[error] C1Holder.Data and BaseHolder.Data
[error] trait Conc extends Abst with C1Holder.Data
[error] ^
[error] one error found
It's saying that (object BaseHolder).Data
is not consistent with (object C1Holder).Data
since although the latter conforms to (trait BaseHolder)#Data
, this is less specific than trait Data
in the singleton instance object BaseHolder
.
Edit. Note that types and values live in different namespaces, so the name BaseHolder
alone is ambiguous, it could refer to either the trait of the object. However, when referring to a type, the "." or "#" symbol disambiguates:
T#Data
always means theData
type member in the typeT
. For example,BaseHolder#Data
would be referring to the traitBaseHolder
.x.Data
always means theData
type member in the objectx
. For example,BaseHolder.Data
would be referring to the singleton objectBaseHolder
.
Note that two instances x
and y
of trait BaseHolder
will have different types x.Data
and y.Data
; this is how path dependent types work. Also note that object BaseHolder extends BaseHolder
is just one particular instance of trait BaseHolder
.
To get your code to compile, make sure (trait C1Holder)#Data
actually conforms to (object BaseHolder).Data
trait BaseHolder {
trait Data
}
object BaseHolder extends BaseHolder
trait C1Holder extends BaseHolder {
trait Data extends BaseHolder.Data // Here BaseHolder refers to singleton object
}
object C1Holder extends C1Holder
trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data
In this example, the traits aren't doing much, so you might want to just go with
object BaseHolder {
trait Data
}
object C1Holder {
trait Data extends BaseHolder.Data
}
trait Abst extends BaseHolder.Data
trait Conc extends Abst with C1Holder.Data
You are treating outer traits as simple containers for your inner traits, almost like one would treat packages. However inner classes and traits have a more intricate relationship with their parent classes.
Inner classes and traits are always associated with an instance of the parent class. It is not possible to create an inner class without a parent instance. In practice inner classes have a hidden reference that points to an instance of the parent class.
In your case the trait Data is associated with the object BaseHolder. Then trait Abst extends BaseHolder.Data, so it is also associated with the object BaseHolder. That means that Abst will reference BaseHolder object as its parent.
On the other hand C1Holder.Data references C1Holder as its parent. So when you are defining Conc it must reference both BaseHolder and C1Holder as a parent. But an inner trait can only have ONE parent. Hence the error.
精彩评论