Reputation: 902
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
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, thenget(k)
returnsSome[V]
, otherwise it returnsNone
.
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
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