Kevin Meredith
Kevin Meredith

Reputation: 41909

Comparing None's of Different Types

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

Answers (4)

Alex Dean
Alex Dean

Reputation: 16075

There are really two questions here:

  1. Why does x == y typecheck in your REPL?
  2. Why do they equal each other?

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

Electric Coffee
Electric Coffee

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 Nones are effectively the same type

Upvotes: 2

choeger
choeger

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

4lex1v
4lex1v

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

Related Questions