Raymond H Lucas
Raymond H Lucas

Reputation: 65

Scala Array Generics vs Vector Generics

So I have been working on a refactor in my project to convert Vector's in my code to Array's. The reason being that my application needs to be very performant, and using while-iterations on Array's is significantly faster than for comprehensions and iterations on Vector's. (see this blog post for details)

However I have run into an issue I can't seem to easily find an answer for. I have tweaked my code to hide implementation details, and just boil down to the code needed to highlight the issue.

The following class structure, when using Vector, compiles totally fine:

sealed abstract class BaseClass {    
  def element: Int
}

sealed abstract class TypeA extends BaseClass {
  def element = 2
  def children: Vector[BaseClass]
}

case class TypeB(element: Int = 2) extends BaseClass
case class TypeAA(children: Vector[TypeA]) extends TypeA
case class TypeAB(children: Vector[TypeB]) extends TypeA

Now, when switching from using Vector to using Array, it no longer compiles:

sealed abstract class BaseClass {
  def element: Int
}

sealed abstract class TypeA extends BaseClass {
  def element = 2
  def children: Array[BaseClass]
}

case class TypeB(element: Int = 2) extends BaseClass
case class TypeAA(children: Array[TypeA]) extends TypeA
case class TypeAB(children: Array[TypeB]) extends TypeA

I get the error: overriding method children in class TypeA of type => Array[BaseClass]; value children has incompatible type for both TypeAA and TypeAB classes.

I have a feeling I need to do an implicit conversion somewhere, but I am relatively new to Scala (only a couple months) and am not sure exactly how to use it.

Sorry if this has been asked elsewhere, I had trouble finding the correct search terms for the issue i am having.

Upvotes: 2

Views: 133

Answers (2)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

This comes from the fact Vector[+A] is covariant in its type parameter A while Array[A] is not, meaning invariant in A

You can work around that fact using F-Bounded Polymorphism:

sealed abstract class TypeA[A :< Type[A]] extends BaseClass {
  def children: Array[A] 
}
case class TypeAA(children: Array[TypeA]) extends TypeA[TypeA]
case class TypeAB(children: Array[TypeB]) extends TypeA[TypeB]

Upvotes: 1

Andrei T.
Andrei T.

Reputation: 2480

I think you need to use _ <: BaseClass instead of using the generic type itself:

sealed abstract class TypeA extends BaseClass {
  def element = 2
  def children: Array[_ <: BaseClass]
}

This happens because the generic type parameter in Array is invariant, while in Vector it is covariant:

final class Array[T]
final class Vector[+A]

Hope that helps you.

Upvotes: 3

Related Questions