Scala/Java interoperability: How to deal with options containing Int/Long (primitive types)?

StackOverflow https://stackoverflow.com/questions/17071061

  •  31-05-2022
  •  | 
  •  

Question

Given a service in Scala:

class ScalaService {
  def process1(s: Option[String], i: Option[Int]) {
    println("1: " + s + ", " + i)
  }
}

which is to be used from Java:

public class Java {
    public static void main(String[] args) {
        ScalaService service = new ScalaService();

        // This works, but it's confusing
        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Object> io = scala.Option.apply((Object) 10);
            service.process1(so, io);
        }

        // Would be OK, but not really nice
        {
            scala.Option<Object> so = scala.Option.apply((Object) "Hello");
            scala.Option<Object> io = scala.Option.apply((Object) 10);
            service.process1(so, io); // Does not compile
        }

        // The preferred way
        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Integer> io = scala.Option.apply(10);
            service.process1(so, io); // Does not compile
        }

    }
}

I'd like to avoid to treat primitive and non-primitive types in a different way.

So I tried to get around this by adding another method:

def process2(s: Option[String], i: Option[java.lang.Integer]) {
  print("2: ")
  process1(s, i.map(v => v.toInt))
}

but this requires a different name for the method. As this could be confusing from the caller's perspective, are there any other possibilities?

I'm using Scala 2.10.1, and Java 1.6

Was it helpful?

Solution

The solution I am going to test is to use a DummyImplicit, so I can have the same method name for both the Scala and the Java method:

class ScalaService {
  // To be called from Scala
  def process(s: Option[String], i: Option[Int])(implicit d: DummyImplicit) {
    println("1: " + s + ", " + i)
  }

  // To be called from Java
  def process(s: Option[String], i: Option[java.lang.Integer]) {
    print("2: ")
    process(s, i.map(v => v.toInt))
  }

to be used from Scala like this:

object ScalaService extends App {
  val s = new ScalaService()
  s.process(Some("Hello"), Some(123))
}

and from Java:

public class Java {
    public static void main(String[] args) {
        ScalaService service = new ScalaService();

        {
            scala.Option<String> so = scala.Option.apply("Hello");
            scala.Option<Integer> io = scala.Option.apply(10);
            service.process(so, io);
        }
    }

}

OTHER TIPS

The method signature would be a bit confusing as well, but you could use pattern matching to handle the various types - something like:

class ScalaService {
  def process1(s: Option[String], i: Option[Any]) {
    i match {
      case Some(i2:Int) => processInternal(s, Some(i2))
      case Some(i2:java.lang.Integer) => processInternal(s, Some(i2.intValue))
      case _ => processInternal(s, None) // or throw exception if you prefer
    }

    def processInternal(s:Option[String], i:Option[Int]) { 
      println("1: " + s + ", " + i) 
    }
  }
}

Also, I am not sure about calling from java, but perhaps an implicit conversion from java.lang.Integer to Int might also work?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top