Scala class implementing Java interface - how to implement method taking array of generic type

55 views Asked by At

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

1

There are 1 answers

0
Dmytro Mitin On BEST ANSWER

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