hiroprotagonist
hiroprotagonist

Reputation: 902

scala mutable.Map put/get handles null's in an unexpected way?

I know one is not supposed to use nulls in scala but sometimes when interoperating with Java it happens. The way a scala mutable map handles this seems off though:

scala> import scala.collection.mutable
import scala.collection.mutable

scala> val m: mutable.Map[String, String] = mutable.Map.empty
m: scala.collection.mutable.Map[String,String] = Map()

scala> m.put("Bogus", null)
res0: Option[String] = None

scala> m.get("Bogus")
res1: Option[String] = Some(null)

scala> m.getOrElse("Bogus", "default")
res2: String = null

I would have expected m.get to return None in this case. Almost seems like a bug, like somewhere in the code there was a Some(v) instead of Option(v)

Is there discussion w/r/t to changing this behavior?

Upvotes: 0

Views: 183

Answers (2)

Andrey Tyukin
Andrey Tyukin

Reputation: 44992

Null is subtype of String:

scala> implicitly[Null <:< String]
res3: Null <:< String = <function1>

Therefore null is a valid String value:

scala> val s: String = null
s: String = null

If you want to store a null as a String in a map, it's your good right.


Compared to Java's Map#get (let's call it javaLikeGet), the Scala's get behaves roughly as follows:

def get(k: K) = if (containsKey(k)) { 
  Some(this.javaLikeGet(k)) 
} else { 
  None 
}

and not like what you have assumed:

def get(k: K) = Option(this.javaLikeGet(k))

The latter version (presumably what you thought) would get a null for an existing key, pass it to Option(...), and return None. But the former version (which imitates how the real implementation works) would notice that the key exists, and wrap the null returned by javaLikeGet into a Some.

The simple and consistent rule is:

If the key k exists, then get(k) returns Some[V], otherwise it returns None.

This is much less surprising than the strange behavior of Java's get that returns null in two entirely different situations.


This is the Billion-Dollar Mistake, but Scala is not the language that is likely to fix it, because it has to interop with Java. My guess is that there is and will be no discussion about changing this behavior, at least not until something fundamentally changes in the entire programming landscape.

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170919

I would have expected m.get to return None in this case.

Why? None would mean the key "Bogus" is not in the map, but you just put it in (with value null).

Java's Map API has problems distinguishing "the value for this key is null" from "this key is not in the map", but Scala's doesn't.

Upvotes: 2

Related Questions