Unable to override Java method (problem with self-bounded generic)

#1

I’m trying to extend a Java class. One of the methods I need to override has a strange parameter:

public void doStuff(Foo input) {...}

Foo is an interface defined as follows:

public interface Foo<T extends Foo<T, U>, U extends Bar<U>> {...}

I’ve never seen a recursively-defined type like this before. I gather this is called a self-bounded generic in Java or F-bounded polymorphism in Scala.

IntelliJ generates the override like this:

override def doStuff(input: Foo[_, _ <: Bar[_]]): Unit = {...}

The presentation compiler seems to accept this, but the code does not actually compile. I get the following error:

method doStuff overrides nothing

I’ve tried adding additional upper type bounds for the Foo parameter. I’ve also tried declaring a type alias for Foo. Nothing has worked so far.

My current workaround is to extend the class in Java and have it call Scala methods that do the actual work (luckily, I don’t need to consume the Foo parameter - I just need to override the method). Of course, this is far from ideal. Is there a way to override the doStuff method in a way that will actually compile?

#2

Doesn’t the error message suggest a type you can use? I once fixed a bug about exactly this.

#3

The error message just suggests methods to override. It doesn’t give any hints about types. (I’m on Scala 2.12.5, if that matters.)

Luckily, the link you posted led me to a solution. The following code compiles:

override def doStuff(input: Foo[T, U] forSome {type T <: Foo[T, U]; type U <: Bar[U]}: Unit = {...}

The presentation compiler doesn’t like the second U; otherwise, everything seems fine.

The forSome keyword is used for something called existential typing. The following links helped me understand this better:

Thanks for your help!

#4

Note that this code might be affected if and when Scala 3 removes existential types: https://contributors.scala-lang.org/t/proposal-to-remove-existential-types-from-the-language/2785

#5

It looks like in Scala 3 you can just write Foo[_, _] and it will work without needing forSome. At least that seems to work now in dotty.