1

In Java, we have defined an ObservableCollection.java like this:

public class ObservableCollection<T> implements Collection<T> {

   public SubscriptionHandle onElementAdded(Consumer<T> onAdded) {
     // ... 
   }
}

And an AgentService.java that returns an ObservableCollection:

public interface AgentService {

    ObservableCollection<? extends Agent> getAgents();

}

Now, I am trying to use this ObservableCollection.java in a Scala project like this:

  def test(service: AgentService): Unit = {
    val onAdded: Consumer[_ <: Agent] = ???
    service.getAgents.onElementAdded(onAdded)
  }

Trying this results in the following compilation error:

type mismatch;
 found   : java.util.function.Consumer[_$1] where type _$1 <: com.xxxx.xx.xx.agent.Agent
 required: java.util.function.Consumer[?0] where type ?0 <: com.xxxx.xx.xx.agent.Agent
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found

This does not make much sense to me. Is there a way I can get this running?

Edit: Using a Cosumer[Agent] results in the following error:

type mismatch;
 found   : java.util.function.Consumer[com.xxxx.xx.xx.agent.Agent]
 required: java.util.function.Consumer[?0] where type ?0 <: com.kuka.cc.si.agent.Agent
Note: com.xxxx.xx.xx.agent.Agent >: ?0, but Java-defined trait Consumer is invariant in type T.
You may wish to investigate a wildcard type such as `_ >: ?0`. (SLS 3.2.10)
    service.getAgents.onElementAdded(onAdded)
                                     ^
one error found
3
  • 1
    Is the error real or just in some IDE? - What happens is you have a Consumer[Agent]? - What happens if you do a dirty cast like service.getAgents.asInstanceOf[ObservableCollection[Agent]] (plus the previous point)? Commented Aug 24, 2020 at 13:40
  • 2
    @LuisMiguelMejíaSuárez It's real. Commented Aug 24, 2020 at 13:58
  • 2
    Yes, the error is real. Regarding the usage of Consumer[Agent]: see edited question. With the dirty cast it works, though! Commented Aug 24, 2020 at 14:20

1 Answer 1

2

The thing is not in Scala-Java interop. The following Scala code doesn't compile either

import java.util.function.Consumer
import java.util

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents: ObservableCollection[_ <: Agent]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test(service: AgentService): Unit = {
  val onAdded: Consumer[_ <: Agent] = ???
  val agents: ObservableCollection[_ <: Agent] = service.getAgents
  agents.onElementAdded(onAdded)
//                      ^^^^^^^
}

//type mismatch;
// found   : java.util.function.Consumer[_$2] where type _$2 <: App.Agent
// required: java.util.function.Consumer[_$3]

You misuse existential types (wildcard generics). The following code can't compile

trait X[T]
trait Y[T] {
  def foo(x: X[T]) = ???
}
val x: X[_] = ???
val y: Y[_] = ???
y.foo(x) // doesn't compile

Both x and y have existential types but foo accepts x of type X[T], where T must be the same as T in the type of y, i.e. Y[T], so you can't guarantee that T are the same.

One way to fix compilation is to add generics to AgentService

trait Agent
trait SubscriptionHandle
trait AgentService[T <: Agent] {
  def getAgents: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T <: Agent](service: AgentService[T]): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}

or to its method

trait Agent
trait SubscriptionHandle
trait AgentService {
  def getAgents[T <: Agent]: ObservableCollection[T]
}
trait ObservableCollection[T] extends util.Collection[T] {
  def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
}

def test[T <: Agent](service: AgentService): Unit = {
  val onAdded: Consumer[T] = ???
  val agents: ObservableCollection[T] = service.getAgents
  agents.onElementAdded(onAdded)
}
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.