halfwarp
halfwarp

Reputation: 1790

Scala generic array

I'm trying to declare a method in an abstract class which receives an Array of generic type T. As such:

abstract class Circle[-T] extends Shape[T] {
   def draw(points: Array[T]): Unit
}

The problem I'm getting is that Scala compiler complaints with:

contravariant type T occurs in invariant position in type Array[T] of value points

So, is there anyway to solve this besides the following?

def draw[U <: T](points: Array[U]): Unit

As a note, I also need to extend this class in Java.

Upvotes: 3

Views: 946

Answers (2)

Vasil Remeniuk
Vasil Remeniuk

Reputation: 20627

Related to this question. You can either skip check for variance

scala> import scala.annotation.unchecked.uncheckedVariance
import scala.annotation.unchecked.uncheckedVariance

scala> abstract class Circle[-T] extends Shape[T @uncheckedVariance] {
     |    def draw(points: Array[_<:T]): Unit
     | }
defined class Circle

or use a view bound

scala> abstract class Circle[T<%T] extends Shape[T]{
     | def draw(points: Array[_<:T]): Unit
     | }
defined class Circle

Upvotes: 3

Kevin Wright
Kevin Wright

Reputation: 49705

Scala's Array maps directly to Java arrays, and is invariant ([T] instead of [+T])

Array is a tricky beast. It's about the only thing that gets reified on the JVM, and it's common knowledge that array variance is purposely broken so that methods like Arrays.sort() could be implemented.

You'd probably be better off using a "true" Java collection here.

To answer the more general question: Yes, if you want to use a parametrised invariant type in a method of a contra-variant class, you have to specify an upper bound in the signature for that method

Upvotes: 4

Related Questions