3

I have a Java interface that looks roughly like this:

public interface Foo {
  public <T> T bar();
}

I want to implement this interface in Scala, where all of my code uses Option. However, since the interface will be used by Java users, I want to return null instead of None. I tried the following:

class FooImpl extends Foo {
  def bar[T](): T = {
    val barOpt: Option[T] = getBar()
    barOpt.orNull
  }
}

This results in the following compile error:

Expression of type Null does not conform to expected type T

This makes sense, type T is unrestricted, it could be an Int or some other type that can't be null. No problem, just add T >: Null and you're done, right?

class FooImpl extends Foo {
  def bar[T >: Null](): T = {
    val barOpt: Option[T] = getBar()
    barOpt.orNull
  }
}    

Nope, still no dice. Now you get a new compile error:

[error]  method bar has incompatible type

It seems that you can't apply any restrictions to T and still implement that interface.

Next, I tried using asInstanceOf:

class FooImpl extends Foo {
  def bar[](): T = {
    val barOpt: Option[T] = getBar()
    barOpt.orNull.asInstanceOf[T]
  }
}    

But that just gets one more error:

Cannot prove that Null <:< T.

Is there any way to make this work?

3
  • try here Commented Jun 20, 2013 at 4:16
  • @BevynQ: As I wrote in the description, the first thing I tried was T >: Null, but that leads to the second error. Commented Jun 20, 2013 at 4:23
  • I don't know scala, but does it support this kind of construct? barOpt.<T>orNull? Commented Jun 20, 2013 at 4:37

4 Answers 4

6

You could use getOrElse and cast to T:

scala> def test[T](t: T): T = { Option(t).getOrElse(null).asInstanceOf[T] }
test: [T](t: T)T

You could move ugly stuff to helper class:

implicit class Defaults[T](val o: Option[T]) extends AnyVal {
  def orDefault(): T = o.getOrElse(null).asInstanceOf[T]
}

def test[T](t: T): T = { Option(t).orDefault }
Sign up to request clarification or add additional context in comments.

1 Comment

I know, but T could be AnyVal. You could hide casting see update.
2

Just an fyi, if you are using play, the same helper already exists in the libs package: https://github.com/playframework/Play20/blob/master/framework/src/play/src/main/java/play/libs/Scala.java#L12

Comments

0

I suspect @senia's answer will prove to be the best option available in pure Scala. If nothing new comes in, I'll mark it as the "official" answer.

For completeness, here is a workaround using a Java class to encapsulate this dirty business, give it a clear name, and, just as importantly, document why it exists:

public class JavaOptionHelper {
  // http://stackoverflow.com/questions/17205142/implement-java-interface-in-scala-with-generics-and-return-null
  public static <T> T toValueOrNull(Option<T> option) {
    if (option.isDefined()) {
      return option.get();
    } else {
      return null;
    }
  }
} 

It can be used as follows:

class FooImpl extends Foo {
  def bar[T](): T = {
    val barOpt: Option[T] = getBar()
    JavaOptionHelper.toValueOrNull(barOpt)
  }
}    

Comments

0

The following worked for me:

scala> def test[T >: Null] = null
test: [T >: Null]=> Null

scala> test[String]
res18: Null = null

scala> def test2[T](x : T)(implicit ev: Null <:< T) = x
test2: [T](x: T)(implicit ev: <:<[Null,T])T

scala> test2("Hallo")
res19: java.lang.String = Hallo

scala> test2(null)
res20: Null = null

There is even a discussion on StackOverflow which covers the topic quite good. For details see here.

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.