Mihai Toader
Mihai Toader

Reputation: 12243

Using recursive generic types defined in java from scala code

I have the following definitions in java code:

An abstract port definition (typed by the concrete port class):

package test;

public class Port<
     PortOptions extends Port.Options, 
     ConcretePort extends Port<PortOptions, ConcretePort>> {

    public interface Options {
    }

}

An port service definition (can do some stuff with the ports via some callback mechanism)

package test;

import java.util.Set;

public class PortService {
    public interface Callback<T> {
        void processData(T data);
    }

    public void methodWithCallback(Callback<Set<Port>> callback) {

    }
}

And i want to register a callback into a port service from scala. What i tried is this:

package test

import test.PortService.Callback
import java.util

class PortServiceCaller {

    def callingMethod() {
        val portService: PortService = new PortService

        portService.methodWithCallback(new Callback[java.util.Set[Port[_, _]]] {
            def processData(data: util.Set[Port[_, _]]) {

            }
        })
    }
}

and it fails miserably with:

error: type mismatch;
found   : java.lang.Object with test.PortService.Callback[java.util.Set[test.Port[_, _]]]
required: test.PortService.Callback[java.util.Set[test.Port[_ <: test.Port.Options, _ <: test.Port[?0,?1]]]]
portService.methodWithCallback(new Callback[java.util.Set[Port[_, _]]] {

The question is: How to write the scala code in order to let me properly call the java service ?

I have looked over the scala typing system and i can't seem to figure it out.

Later edit:

The solution is actually simple enough:

Declare the callback method as:

    public void methodWithCallback(Callback<Set<Port<?, ?>>> callback) {

    }

and call it from scala like this:

    portService.methodWithCallback(new Callback[java.util.Set[Port[_, _]]] {
        def processData(data: java.util.Set[Port[_, _]]) {
        }
    })

And also makes sense given the type system of both languages.

Upvotes: 3

Views: 394

Answers (1)

Edmondo
Edmondo

Reputation: 20080

What you are doing in Java is something dangerous and your code compiles only because Java compiler is lazy and won't check it. When you write :

   public void methodWithCallback(Callback<Set<Port>> callback) {

    }

You are basically throwing away all the type information about Port:

Port<PortOptions extends Port.Options, ConcretePort extends Port<PortOptions, ConcretePort>>

The whole information is not going to be available, and the Java compiler let you omit the type parameters. In scala this is not possible, and not only you have to express the type parameters but also the type constraints correctly. The first question here is why you are writing Port without not even saying that there some unknown types there.

public void methodWithCallback(Callback<Set<Port<?,?>>> callback) {

}

would be the right way of writing it.

If now you want to express the bounds relationship among multiple unknown types, you cannot use the compact _ for existential types which is suitable for simple bounds, but you have to use forSome

  class Port[A,B<:A]

  def myMethod(a:Port[A,B]forSome {type B; type B<:A})

However, as I tend to say, ending up in using these patterns is a such that your design is weak and you might have a cleaner and more elegant way to solve your problem. What is the point of using generics if you then need to throw your information about type-safety away?

Upvotes: 3

Related Questions