broun
broun

Reputation: 2593

Scala Option type not inferred as expected

I'm writing a function to get an entry from a JSONObject. Since it is JSON the entry by the input name may or may not exist and so the function return an Option which will be None when the Try fails or if the value is NULL on success. The function fails to compile and errors about incorrect return type.

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] = {
  Try(jsonObject.get(name))
    .map(x => if(JSONObject.NULL.equals(x)) None else x.asInstanceOf[T])
    .toOption
}

Error:

Expression of type Option[Any] doesn't conform to expected type Option[T]

Can someone tell me what I'm doing wrong here? Also, is this the idiomatic way to approach the problem?

Update:

Changing to the below works

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] = {
    Try(jsonObject.get(name))
      .filter(!JSONObject.NULL.equals(_))
      .map(_.asInstanceOf[T])
      .toOption
}

Upvotes: 4

Views: 7009

Answers (2)

Binzi Cao
Binzi Cao

Reputation: 1085

I don't think you need the null check, and "None" and "T" are two possible result in the map, so the type will be mapped to Any instead of "T" in your code. Check this:

Try(jsonObject.get(name)).map( _.asInstanceOf[T]).toOption

Then you might need something like this:

val NullJson:Option[T] = None
Try(jsonObject.get(name)).map( x=>if(x.equals(null)) NullJson else Option(x.asInstanceOf[T])).toOption.flatten

Upvotes: 0

Michael Zajac
Michael Zajac

Reputation: 55569

The problem is with this line:

.map( x => if(x.equals(null)) None else x.asInstanceOf[T])
This has type `Option[Nothing]` ^         ^ This has type `T`

You have both an Option[Nothing] and a T in the if/else statement. The result type of if/else is the least upper-bound (the nearest common type) of the result type of if and the result type of else. In this case, they have nothing in common but Any. So the the result is Try[Any] which gets converted to Option[Any] by toOption.

If you really need to check for null, use filter instead.

def tryGet[T](jsonObject: JSONObject, name: String): Option[T] =
    Try(jsonObject.get(name))
        .map(_.asInstanceOf[T])
        .filter(_ != null)
        .toOption

Upvotes: 4

Related Questions