开发者

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:

  1. T#Data always means the Data type member in the type T. For example, BaseHolder#Data would be referring to the trait BaseHolder.

  2. x.Data always means the Data type member in the object x. For example, BaseHolder.Data would be referring to the singleton object BaseHolder.

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜