0

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
  • Your attempt 2 would work in Scala 3. See update with some explanation Commented Apr 14, 2023 at 14:42

1 Answer 1

2

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

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

Comments

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.