How to override abstract trait type in subclasses

74 Views Asked by At

I would like to define a trait with a method that returns a generic type value and then define a class hierarchy where a parent class defines a specific generic type value and the subclass defines a different one, like so:

trait Thingy {
  type T
  def doIt(): T
}

class A extends Thingy {
  override type T = Array[Int]
  override def doIt(): T = {
    Array[Int](1, 2, 3)
  }
}

class B extends A {
  override type T = Array[String]
  def doIt(): T = {
    Array[String]("stringy")
  }
}

val aa = new A()
println(aa.doIt().length)

val bb = new B()
println(bb.doIt()(0))

This generates compile errors

ScalaFiddle.scala:16: error: overriding type T in class A, which equals scala.this.Array[scala.this.Int];
 type T has incompatible type;
 found   : B.this.T
    (which expands to)  scala.this.Array[String]
 required: A.this.T
    (which expands to)  scala.this.Array[scala.this.Int]
    override type T = Array[String]
                  ^
ScalaFiddle.scala:17: error: overriding method doIt in class A of type ()B.this.T;
 method doIt needs `override' modifier;
 found   : ()B.this.T
    (which expands to)  ()scala.this.Array[String]
 required: ()A.this.T
    (which expands to)  ()scala.this.Array[scala.this.Int]
    def doIt(): T = {
        ^

I have tried parameterized types, abstract classes, and traits but I can't seem to get it right. Can someone explain if there is a way to do it?

Adding use case to answer Luis Miguel Mejía Suárez

I'm simply trying to use inheritance to inherit common methods while maintaining 2 different data structures to represent the internal state of each class. Say the parent class is a Grid that represents its internal data structure with a 2D Array of Cells of known dimensions

class Grid(var rows, var columns) {
  protected var _grid: Array[Array[Cell]] = makeGrid()
  def makeGrid(): Array[Array[Cell]] = {
    var g = Array.ofDim[Cell](rows, columns)
    // populate g
    g
  }
}

and I have a subclass that needs to represent the grid with a mutable ArrayBuffer:

class OtherGrid(var rows) extends Grid(rows, 1) {
  protected var _grid: ArrayBuffer[ArrayBuffer[Cell]] = makeGrid()
  override def makeGrid(): ArrayBuffer[ArrayBuffer[Cell]] = {
    // initialize and populate the grid
  }
}

Is this the wrong way to go about things in a functional programming language?

0

There are 0 best solutions below