robbbert
robbbert

Reputation: 2193

Scala: Overwriting a Generic Java Method that returns null

I need to override the following Java method in a Scala class:

public class Test<T> {
    public T test(T o, boolean x) {
        if (x) {
            return o;
        }
        return null;
    }
}

With the following approach (in Scala), the compiler complains, "Expression of type Null doesn't conform to expected type T":

class Test2[T] extends Test[T] {
  override def test(o: T, x: Boolean): T = {
    if (x) {
      return o
    }
    return null
  }
}

I've also tried to define Option[T] as return value, but then again, the compiler complains that the method signatures wouldn't match.

Any idea? - Thanks!


Edit:

Daniel's suggestion works for the problem as originally posted; however, my actual problem unfortunately still differs slightly (by having the generic type parameter in the method, not class, definition) (sorry):

Java:

public class Test {
    public <T> T test(T o, boolean x) {
        if (x) {
            return o;
        }
        return null;
    }
}

Scala:

class Test2 extends Test {
  override def test[T >: Null](o: T, x: Boolean): T = {
    if (x) {
      return o
    }
    return null
  }
}

Compilation again fails with the error, "Expression of type Null doesn't conform to expected type T".
(I believe that's because the override does not cover any possibilities - i.e., something of type Nothing could be passed to Test.test(..) - well, could it? ;-) )

What does work is throwing a RuntimeException instead of returning null as Ricky suggested; nonetheless, I'd be grateful for further input.

Thanks all!

Upvotes: 7

Views: 4959

Answers (3)

Nikolay Ivanov
Nikolay Ivanov

Reputation: 8935

Have you considered using Option instead following will work:

class Test{
  def test[T] (value:T,flag :Boolean) :Option[T] = {
    if (flag){
      Some(value)
    }else{
      None
    }
  }
}

It will help to distinguish situations like test(null,true) and test(null,false)

Upvotes: 0

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297295

You need this:

class Test2[T >: Null] extends Test[T] {

The problem is that Nothing cannot be null, and, being the subtype of everything, it is a valid value of T. So you need to specify Null as the lower bound.

EDIT

Unfortunately, there's no good way around your actual problem. In this case, you'll have to write null.asInstanceOf[T] and leave it at that.

And, yes, you can call it with non-nullable types. Try this, for example:

object Test3 {
  val test = new Test();
  val x: Int = test.test(5, false);
}

Upvotes: 13

Ricky Clarkson
Ricky Clarkson

Reputation: 2939

T is unrestricted, so it can be any type including Int, Double, Float or other subtypes of AnyVal which cannot be null.

You probably want class Test2[T <: AnyRef] rather than class Test[T], declaring that T is any type that is AnyRef (basically java.lang.Object) or any subtype thereof.

In general, try to return something more useful than null, or throw an exception. There may be cases where you have to do it because of some third party API, but if that isn't the case, see if there's a better way. null doesn't appear in the method's type, whereas Option does, for instance.

Upvotes: 6

Related Questions