2

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.

1
  • 1
    The problem is that Array is invariant in Scala while Vector is covariant. This means that Vector[TypeA] is a subtype of Vector[BaseClass], but Array[TypeA] is not a subtype of Array[BaseClass]. Commented Mar 28, 2017 at 17:15

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Yeah, sorry, I went through the question in a rush. The problem is with generic types - you should use an upper bound to achieve that.
yes your revision works as expected, thanks so much!
1

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]

1 Comment

thank you! I tried to upvote but could not due to account restrictions. I accepted Andrei answer as he was first. thanks for the help though!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.