Reputation:
While reading and trying to get all the concepts behind scalable components in Scala from this, i still can't fully understand why this example should have self type:
abstract class Graph {
type Node <: NodeLike
trait NodeLike { // without self: Node => won't compile
def connectWith(n: Node) =
new Edge(this, n)
}
class Edge(from: Node, to: Node)
}
abstract type Node
is a subtype of NodeLike
and this
is an object of type NodeLike
which suites according to the given upper constraint. Any detailed explanation would be appreciated.
Upvotes: 0
Views: 91
Reputation: 31724
Well it rightly fails because of the bound Node <: NodeLike
. When you are doing new Edge(this,n)
, you are simply passing argument types as NodeLike, Node
to Edge. But your Edge
expects 'Node,Node`:
class Edge(from: Node, to: Node)
i.e. you are trying to pass NodeLike
to Node
(NodeLike is super type of Node). Thats like passing an Animal to a function that is expecting Dog (The issue, is if it is allowed then you could pass any Animal including cat to one expecting Dog)
A work around would be :
abstract class Graph {
type Node <: NodeLike
trait NodeLike { // without self: Node => won't compile
def connectWith(n: Node) =
new Edge(this, n)
}
class Edge(from: NodeLike, to: Node)
}
Or another way would be as you have mentioned where you explicitly guarantee that the argument you are passing is of type Node and not NodeLike.
Upvotes: 3
Reputation: 144126
In the definition
def connectWith(n: Node) = new Edge(this, n)
this
has type NodeLike
, however the constructor for Edge
requires that from
is of type Node
, which is a subtype of NodeLike
. You need the self type annotation to ensure that this
has the required type of Node
.
Upvotes: 0