6

I have some Scala code that needs to call a Java API

The Java API takes arguments that may be null. My Scala, of course, uses Option.

For example, let's say I have a Java object constructor Foo(Integer) where the Integer may be null. I want to call it given a Scala bar: Option[Int].

I tried this

import scala.collection.JavaConversions._
import scala.collection.JavaConverters._

val foo = Foo( bar.getOrElse(null) )

But got this compile error

Error:(335, 44) type mismatch;
  found   : Any
  required: Integer
  bar.getOrElse(null),

What is the correct idiom for doing this?

3 Answers 3

5

You don't need a Java method to reproduce this problem:

scala> import scala.collection.JavaConversions._
import scala.collection.JavaConversions._

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

scala> class Foo(a: java.lang.Integer)
defined class Foo

scala> val bar: Option[Int] = Some(5)
bar: Option[Int] = Some(5)

scala> new Foo(bar.getOrElse(null))
<console>:16: error: type mismatch;
 found   : Any
 required: Integer
              new Foo(bar.getOrElse(null))
                                   ^

The problem is that Int can't be null, so the type of bar.getOrElse(null) is Any.

scala> bar.getOrElse(null)
res0: Any = 5

scala> bar.orNull
<console>:15: error: Cannot prove that Null <:< Int.
              bar.orNull
                  ^

So you've got to convert the Option's type parameter to something that can be null before you unwrap it in a nullable way.

Quickest way I can think of immediately:

scala> new Foo(bar.map(x => x: java.lang.Integer).orNull)
res18: Foo = Foo@cdc45e

Edit: Here, I thought of a more general way to do it!

implicit class RichOption[A](o: Option[A]) {
    def toRef[B >: Null](implicit f: A => B): B = o.map(f).orNull
}

Now you can write new Foo(bar.toRef) :)

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Chris. I understand now. I wonder if some implicit could/should be added JavaConverters to make calling Java easier, and avoid the temptation to use NULL in your Scala code ;-)
Thumbs up, but I would call it toRef. x.toRef[Integer]. The SO nanny doesn't allow increment operator in comments. It's weird being back in Kindergarten, the chairs are so small.
3

No sooner do I post the question, than I spot the answer in the related list (sorry)

Here's a solution

val foo = Foo(bar.getOrElse(null).asInstanceOf[java.lang.Integer])

Kind of clunky. Anyone have anything better?

1 Comment

The complaint I have this this solution is that asInstanceOf masks type errors. If bar is an Option[String], this compiles but throws ClassCastException.
3

More chatter:

scala> import runtime.BoxesRunTime.boxToInteger
import runtime.BoxesRunTime.boxToInteger

scala> val x = Some(42)
x: Some[Int] = Some(42)

scala> val y: Option[Int] = None
y: Option[Int] = None

scala> x.fold(null: Integer)(boxToInteger)
res0: Integer = 42

scala> y.fold(null: Integer)(boxToInteger)
res1: Integer = null

Of course it's better to

scala> x.fold(null: Integer)(i => i: Integer)
res2: Integer = 42

and even better

scala> x.fold[Integer](null)(identity)
res3: Integer = 42

scala> y.fold[Integer](null)(identity)
res4: Integer = null

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.