Tutorials type
First, look at the so-called native types . Andrew Rollins' blog provides a nice introduction to Self Type Annotations vs. Inheritance .
Basically, type self written as
trait Foo { self: SomeType => ... }
says that the Foo attribute can only be mixed in a class that also implements SomeType . The difference between inheritance and homing is also well explained here .
Often Dependency Injection types use type types, such as Cake Pattern .
Type restrictions
Given the type definition:
class TreeNode[BaseType <: TreeNode[BaseType]] { self: BaseType with Product => // ... }
The definition of TreeNode[BaseType <: TreeNode[BaseType]] states: TreeNode is entered so that the parameter of type BaseType at least (in the sense of a subclass) also a TreeNode[BaseType] . Roughly speaking, this means: the type parameter must also be a TreeNode .
In this case, the self-test requires that the TreeNode subclass be "enabled" if it also provides a Product .
Case studies
Example 1
class IntTreeNode extends TreeNode[Int] {}
not compiled due to:
- An argument of type
Int does not comply with the restrictions of the parameters of the TreeNode class, i.e. [BaseType <: TreeNode[BaseType]] - Illegal inheritance due to the restriction of the type of independent type.
Example 2
class IntTreeNode2 extends TreeNode[IntTreeNode2]
not compiled due to:
- Illegal inheritance due to the restriction of the type of independent type.
Example 3
class TupleTreeNode extends TreeNode[TupleTreeNode] with Product1[Int] { // implementation just to be a `Product1` override def _1: Int = ??? override def canEqual(that: Any): Boolean = ??? }
does compilation because of:
- type restriction on
BaseType and self-type are executed. So this is what the initial definition requires.
Note
There is also an example similar to yours (Catalyst) at docs.scala-lang.org
source share