You can rewrite trait B
with (more later about your goal, which, I think, is a bit different)
trait B extends A {
type MyType <: BInner with AInner
}
And this makes total sense. A value of type B#MyType
can be seen as either a BInner
or a AInner
.
You don't need to repeat Abstract
because A
is already a subclass of Abstract
. You don't have to write override
as this is implicit for a type declaration. So the question is why A#MyType
is not working as AInner
?
Here is what the scala language spec says about volatile types.
3.6 Volatile Types
Type volatility approximates the possibility that a type parameter or abstract type instance of a type does not have any
non-null values. As explained in (§3.1), a value member of a volatile
type cannot appear in a path. A type is volatile if it falls into one
of four categories: A compound type T1 with ... with Tn {R } is
volatile if one of the following two conditions hold.
1. One of T2, ..., Tn is a type parameter or abstract type, or
2. T1 is an abstract type and and either the refinement R or a type Tj for j > 1 contributes an abstract member to the compound type, or
3. one of T1, ..., Tn is a singleton type. Here, a type S contributes an abstract member to a type T if S contains an abstract member that
is also a member of T . A refinement R contributes an abstract member
to a type T if R contains an abstract declaration which is also a
member of T . A type designator is volatile if it is an alias of a
volatile type, or if it designates a type parameter or abstract type
that has a volatile type as its upper bound. A singleton type p.type
is volatile, if the underlying type of path p is volatile. An
existential type T forSome {Q } is volatile if T is volatile.
Other important item mentioned by the spec is about abstract type overriding:
Another restriction applies to abstract type members: An abstract type member with a volatile type (§3.6) as its upper bound may not
override an abstract type member which does not have a volatile upper
bound.
The compiler error is:
error: overriding type MyType in trait A with bounds <: AInner;
type MyType is a volatile type; cannot override a type with non-volatile upper bound
This is consistent with the spec. BInner with A#MyType
is volatile. Before that MyType
had a non-volatile as Any
.
The matter is that a type in the scala type system must have a unique meaning. An abstract type can be thought as a type which declaration is deferred to a subclass. Therefore there is no problem for declaring values of an abstract type when it is still abstract. On the other hand if we have a type like BInner with A#MyType
, this type may have several meaning. It is called volatile and it does not makes sense to have a non null value of this type, as it could have as many types as subclasses instantiating the MyType
abstract type. To simplify things, we could think of a volatile type as a type not being a subtype of Any
(and volatile as being a subtype Any
). We therefore have a contradiction that the compiler mentions.
Coming back to your goal, which you stated as
What I'm trying to achieve here(in trait B) is to further restrict the type MyType declared > in Abstract, so any value of type MyType must extend all the MyTypes in the mixin tree.
You can achieve this thanks to inner traits like this.
trait Abstract {
type MyType
}
trait B extends Abstract {
trait MyType {
def bMethod : Int
}
}
trait A extends B {
trait MyType extends super.MyType {
}
}
Well I hope this somewhat what you're looking for.