-2

I'm trying to call my Scala Util object from Java code:

Main.java

Set<Long> items = new HashSet<Long>();
// fill up items with Long
MyUtil.foo(100, items);

Util.scala

object Foo {
 type Id = Long
 def foo(id: Id, items: scala.collection.mutable.Set[Id]) 

Here's the compile-time error:

  could not parse error message:   
  required: long,scala.collection.mutable.Set<Object>
  found: Long,java.util.Set<Long>
  reason: actual argument java.util.Set<Long> cannot be converted to 
      scala.collection.mutable.Set<Object> by method invocation conversion`

From reading these Java to Scala Collections docs, I am using a mutable Set rather than the default, immutable Set:

scala.collection.mutable.Set <=> java.util.Set

But, I don't understand the error message. By using a Long (boxed long) in my Java code, why is a Set<Long> found?

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

2 Answers2

2

Demonstrating what the commenter said:

scala> import collection.JavaConverters._
import collection.JavaConverters._

scala> val js = (1 to 10).toSet.asJava
js: java.util.Set[Int] = [5, 10, 1, 6, 9, 2, 7, 3, 8, 4]

scala> def f(is: collection.mutable.Set[Int]) = is.size
f: (is: scala.collection.mutable.Set[Int])Int

scala> def g(js: java.util.Set[Int]) = f(js.asScala)
g: (js: java.util.Set[Int])Int

scala> g(js)
res0: Int = 10
som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • Hi @som-snytt. Would `error: value toSet is not a member of java.util.Set[Long]` show up here: `foo(items: java.util.Set[Long]) { val scalaSet = items.toSet }` due to the `java.util.Set` type? – Kevin Meredith Jan 30 '14 at 22:03
  • Yes. So the preferred idiom is to use JavaConverters (not Conversions), and call asJava and asScala to convert, as shown. Then in your method that takes a Java set, call asScala on it first. You could also call js.asScala.toSet to build an immutable Set. – som-snytt Jan 31 '14 at 00:03
  • I ran into another error that may or may not be related to this one - http://stackoverflow.com/questions/21483121/calling-scala-method-from-java-setobject-or-setlong. If you get time, please take a look. Thanks – Kevin Meredith Jan 31 '14 at 15:05
1

Working with Scala collections and type aliases from Java code (not the converse, as som-snytt showed :) is going to be at least nasty, most likely very painful, and quite possibly impossible.

If you're able to modify the Scala side of the API, I'd recommend adding a Java-friendlier API to it. If not, I guess you could build an adapter layer in Scala that proxies Java clients through to the native Scala API.

So, something like:

// Original Scala
object Foo {
  type Id = Long
  def foo(id: Id, items: scala.collection.mutable.Set[Id]) 
}

// Java adapter -- generics might be made to work on the Java side, 
// but Long is particularly problematic, so we'll just force it here
object FooJ {
  import scala.collection.JavaConverters._

  def foo(id: Long, items: java.util.Set[Long]) = {
    Foo.foo(id, items.asScala)
  }
}
Community
  • 1
  • 1
Alex Cruise
  • 7,939
  • 1
  • 27
  • 40