Reputation: 2796
class AbstractNode
class Node extends AbstractNode {
def update() {
// update something here
}
}
class AbstractGraph {
val allNodes = ArrayBuffer[AbstractNode]()
}
class Graph extends AbstractGraph {
override val allNodes = ArrayBuffer[Node]()
def updateAll() {
allNodes.foreach(_.update())
}
}
Above produces error:
overriding value allNodes in class AbstractGraph of type scala.collection.mutable.ArrayBuffer[AbstractNode];
value allNodes has incompatible type
override val allNodes = ArrayBuffer[Node]()
^
What is the correct way of adding update
method to Node? Is this related to A Tour of Scala: Explicitly Typed Self References?
Upvotes: 2
Views: 2050
Reputation: 297205
Try to use immutable collections all around. It will be much easier, because immutable collections can be covariant.
Upvotes: 0
Reputation: 18859
Because ArrayBuffer[Node] is not a subtype of ArrayBuffer[AbstraceNode]. It has something to do with Variances. In scala A is a subtype of B doesn't mean S[A] is a subtype of S[B]. It may lead to S[A] subtype S[B] or S[B] subtype S[A] or nothing.
For example:
scala> class A
defined class A
scala> class B extends A
defined class B
scala> class S1[+T]
defined class S1
scala> val s11: S1[A] = null.asInstanceOf[S1[B]]
s11: S1[A] = null
scala> val s12: S1[B] = null.asInstanceOf[S1[A]]
<console>:8: error: type mismatch;
found : S1[A]
required: S1[B]
val s12: S1[B] = null.asInstanceOf[S1[A]]
^
scala> class S2[-T]
defined class S2
scala> val s21: S2[A] = null.asInstanceOf[S2[B]]
<console>:8: error: type mismatch;
found : S2[B]
required: S2[A]
val s21: S2[A] = null.asInstanceOf[S2[B]]
^
scala> val s22: S2[B] = null.asInstanceOf[S2[A]]
s22: S2[B] = null
scala> class S3[T]
defined class S3
scala> val s31: S3[A] = null.asInstanceOf[S3[B]]
<console>:8: error: type mismatch;
found : S3[B]
required: S3[A]
Note: B <: A, but class S3 is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
val s31: S3[A] = null.asInstanceOf[S3[B]]
^
scala> val s32: S3[B] = null.asInstanceOf[S3[A]]
<console>:8: error: type mismatch;
found : S3[A]
required: S3[B]
Note: A >: B, but class S3 is invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
val s32: S3[B] = null.asInstanceOf[S3[A]]
Edit:
class AbstractNode
class Node extends AbstractNode {
def update() {
// update something here
}
}
class AbstractGraph[T <: AbstractNode] {
val allNodes = ArrayBuffer[T]()
}
class Graph extends AbstractGraph[Node] {
def updateAll() {
allNodes.foreach(_.update())
}
}
Upvotes: 7
Reputation: 8898
I'm pretty new to Scala as well but I think what you want here are abstract types which are used in the code examples on the page you linked to. I think the reason you're getting that error is you're trying to narrow the type of allNodes from AbstractNode to Node. This means that your concrete implementation is type incompatible with AbstractGraph and you could not use an instance of Graph anywhere you could use an AbstractGraph.
If you want to do this then you want to use abstract types. An abstract type says that there will exist some type and the concrete implementation must instantiate it. In the code below the AbstractGraph says that a concrete implementation must specify a type node
which is a subtype of AbstractNode and Graph specifies that this is type Node
.
import scala.collection.mutable.ArrayBuffer class AbstractNode class Node extends AbstractNode { def update() { // update something here } } class AbstractGraph { type node <: AbstractNode val allNodes = new ArrayBuffer[node]() } class Graph extends AbstractGraph { override type node = Node def updateAll() { allNodes.foreach(_.update()) } }
Upvotes: 2