Reputation: 41909
Why does each None
(of different Option
types) evaluate to true?
scala> val x: Option[String] = None
x: Option[String] = None
scala> val y: Option[Int] = None
y: Option[Int] = None
Both x
and y
are Option
's of separate types, yet their None
's equal each other.
scala> x == y
res0: Boolean = true
Why?
Upvotes: 3
Views: 1799
Reputation: 16075
There are really two questions here:
x == y
typecheck in your REPL?x == y
compiles because ==
in Scala is not type safe:
scala> "x" == 1
res4: Boolean = false
So why do they equal each other? An Option
in Scala is conceptually similar to an Algebraic Data Type in Haskell:
data Maybe a = Nothing | Just a
But if you look at the Option.scala source, you'll see that an Option
is defined (simplifying somewhat) as:
sealed abstract class Option[+A] extends Product with Serializable
final case class Some[+A](x: A) extends Option[A]
case object None extends Option[Nothing]
On the Some
side, you can see a case class with parameterized type +A
- so a someish Option[Int]
becomes Some[Int]
.
However, on the None
side, you see an Option[Nothing]
object, so a noneish Option[Int]
and a noneish Option[String]
both become an Option[Nothing]
object, and hence equal each other.
As @TravisBrown points out, Scalaz catches this much earlier, at compile time:
scala> import scalaz._
scala> import Scalaz._
scala> val x: Option[String] = None
scala> val y: Option[Int] = None
scala> x === y
<console>:16: error: could not find implicit value for parameter F0: scalaz.Equal[Object]
x === y
scala> val z: Option[String] = None
scala> x === z
res3: Boolean = true
Upvotes: 3
Reputation: 12104
Option
is (roughly speaking) implemented like this:
trait Option[+A]
case class Some[A](value: A) extends Option[A]
case object None extends Option[Nothing]
Because None
is an object, (a singleton in java terms), there's only one instance of it, and because Nothing
is at the very bottom of the type hierarchy, meaning it's a subtype of EVERY type in Scala (even null), the two None
s are effectively the same type
Upvotes: 2
Reputation: 3567
Without looking at the actual implementation, I would assume that None
is actually a case object. Hence, there is exactly one None
in your memory. So both are the same thing. And identity obviously implies equality.
As to the question, why you can actually compare the two: This is due to Scala's subtyping: Every Object
has an equals
method, and this method is what you are using with the ==
operator.
edit: I found the implementation On github you can see, that None is indeed a case object. There also is no equals() method, so you are using the one which is automatically generated for case classes. Hence the comment below about type erasure also applies to your Some()
case.
Upvotes: 8
Reputation: 21557
And 1 == "string"
returns false
. Standard equality check in Scala is not type safe, i.e:
final def ==(arg0: Any): Boolean
If you want typesafety use ===
with Equal
Typeclass from scalaz.
Upvotes: 3