I hava a Java interface:
public interface FooJava<Element> {
void consume(Element[] elements);
// more methods
}
and I want to implement it in Scala:
// attempt 1
class BarScala[T] extends FooJava[T] {
override def consume(elements: Array[T]): Unit = ???
}
// attempt 2
class BarScala[T <: AnyRef] extends FooJava[T] {
override def consume(elements: Array[T]): Unit = ???
}
In both attempts I get the same compilation error:
class BarScala needs to be abstract, since method consume in trait FooJava of type (elements: Array[T with Object])Unit is not defined
(Note that Array[Element with Object] does not match Array[T]: their type parameters differ)
I don't own the Java class. How can I define my Scala class to avoid this error?
I'm on Scala 2.12
Try
class BarScala[T] extends FooJava[T] {
override def consume(elements: Array[T with Object]): Unit = ???
}
or
class BarScala[T] extends FooJava[T] {
override def consume(elements: Array[T with AnyRef]): Unit = ???
}
The behavior can be reproduced even purely in Scala. Although for T <: Upper
, T with Upper =:= T
, we can't replace T with Upper
with just T
in overriding method
trait Foo[T, F[_], Upper] {
def consume(elements: F[T with Upper]): Unit
}
class Bar[T <: Upper, F[_], Upper] extends Foo[T, F, Upper] {
implicitly[(T with Upper) =:= T] // compiles
implicitly[F[T with Upper] =:= F[T]] // compiles
override def consume(elements: F[T with Upper]): Unit = ??? // compiles
//override def consume(elements: F[T]): Unit = ??? // doesn't compile
// method consume overrides nothing
// class Bar needs to be abstract. Missing implementation for member of trait Foo
}
Similarly,
trait Foo[T, F[_], Upper] {
type X <: T with Upper
type Y >: T with Upper
type Z = T with Upper
type Z1 >: T with Upper <: T with Upper
type Z2 >: T <: T
}
class Bar[T <: Upper, F[_], Upper] extends Foo[T, F, Upper] {
override type X <: T // compiles
override type Y >: T // compiles
//override type Z = T // doesn't compile: incompatible type in overriding, Equivalent type required when overriding a type alias
override type Z1 = T // compiles
override type Z2 = T with Upper // compiles
}
Probably the thing is that for T <: Upper
, T with Upper <: T
and T <: T with Upper
https://scala-lang.org/files/archive/spec/2.13/03-types.html#conformance
but not T with Upper ≡ T
https://scala-lang.org/files/archive/spec/2.13/03-types.html#equivalence
This behavior is changed in Scala 3 https://scastie.scala-lang.org/DmytroMitin/LHhlufv8ReqoN6w2ZL0BLQ/1