TautrimasPajarskas
TautrimasPajarskas

Reputation: 2796

Scala: overriding collection type

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

Answers (3)

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297205

Try to use immutable collections all around. It will be much easier, because immutable collections can be covariant.

Upvotes: 0

Eastsun
Eastsun

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

asm
asm

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

Related Questions