I want to to extend a trait within a trait, like this:
trait NodeTypes {
trait Node {
def allNodesHaveThis: Int
}
}
trait ScrumptiousTypes e
This isn't meant to be an answer. It's just quotations from and interpretations of the spec, which are too long to fit readably into comments (prompted by johny's answer). I'm spelling out my interpretations so you might be able to spot where I went wrong. Maybe this will lead to an explanation or to a way to chain extensions of traits within traits (or to a bug report in the unlikely event that my interpretation turns out to be right).
§6.5 This and Super: A reference super.m refers statically to a method or type m in the least proper supertype of the innermost template containing the reference. It evaluates to the member m′ in the actual supertype of that template which is equal to m or which overrides m.
The big question is: What does the spec say that super.Node
inside YummyTypes
refers to? To find out, we'll need to know the definitions of the spec-specific terms used above:
§5.1 Templates: A template defines the type signature, behavior and initial state of a trait or class of objects or of a single object.
So, a template is what we'd ordinarily call an object, class, or trait definition.
§5.4 Traits: A trait is a class that is meant to be added to some other class as a mixin. … The least proper supertype of a template is the class type or compound type consisting of all its parent class types.
§5.1.2 Class Linearization: Let C be a class with template C1
with ... with
Cn. The linearization of C, L(C), is defined as follows:
L(C) = C,L(Cn) +⃗ … +⃗ L(C1)
Here +⃗ denotes concatenation where elements of the right operand replace identical elements of the left operand.
I take this to mean that the linearization is a sequence of classes, which you get by starting with the class being defined and then reading the with types from right to left. When two classes in the linearization define a member or type with the same name (an “element”), the class that comes first “wins”.
So, the linearization of Graph
should be Graph
,YummyTypes
,ScrumptiousTypes
,NodeTypes
, followed by standard stuff like Any
. Indeed, this is confirmed when I modify Graph
like this:
object Graph extends ScrumptiousTypes with YummyTypes {
case class Node() extends super.Node { /* … */ }
typeOf[Graph.type].baseClasses foreach { s => println(s.fullName) }
}
which produces:
Graph
YummyTypes
ScrumptiousTypes
NodeTypes
java.lang.Object
scala.Any
§5.4 Traits: Assume a trait D defines some aspect of an instance x of type C (i.e. D is a base class of C). Then the actual supertype of D in x is the compound type consisting of all the base classes in L(C) that succeed D. The actual supertype gives the context for resolving a super reference in a trait. Note that the actual supertype depends on the type to which the trait is added in a mixin composition; it is not statically known at the time the trait is defined.
I take this to mean that the "actual" least proper supertype of a mixed-in trait is determined by the type of the actual object that the trait is mixed into (Graph
in my example), not necessarily a supertype that the trait's definition explicitly extends (NodeTypes
in my example).
So, it would appear that the actual supertype of YummyTypes
in Graph
should be ScrumptiousTypes
. And so, the actual supertype of YummyTypes.Node
in Graph
should be ScrumptiousTypes.Node
.
However, adding this line to Graph
:
typeOf[Node].baseClasses foreach { s => println(s.fullName) }
produces:
Graph.Node
scala.Serializable
java.io.Serializable
scala.Product
scala.Equals
YummyTypes.Node
NodeTypes.Node
java.lang.Object
scala.Any
ScrumptiousTypes.Node
is missing. Apparently, inside YummyTypes
, super.Node
does not refer to Node
in YummyTypes
' actual least proper supertype.
However, if I add:
abstract override def text = super.text + " ScrumptiousTypes" // in ScrumptiousTypes
abstract override def text = super.text + " YummyTypes" // in YummyTypes
printing text
in Graph
produces:
ScrumptiousTypes YummyTypes
demonstrating that inside YummyTypes
in Graph
, super.text
does refer to ScrumptiousTypes.text
!