views:

132

answers:

2

Hi,

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.

+5  A: 

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

Kevin Wright
Note that Java arrays are covariant, weird as that might seem. Scala's invariantness results in some problems, particularly with methods expecting `Object[]`.
Daniel
+5  A: 

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
Vasil Remeniuk
+1, didn't know about `uncheckedVariance` annotation.
missingfaktor
@missingfactor huh, scala has too much to offer :)
Vasil Remeniuk
Hm, although it compiles, when calling the draw method from Java I get the following error: Circle: method <init>()V not found
halfwarp
@halfwarp did you use the annotation or view bounds?
Vasil Remeniuk