5

I am studying Scala and ran into the following puzzle.

I can define the following case classes:

abstract class Expr
case class Number(n: Int) extends Expr

When I create two instances from the class Number and compare them

val x1 = Number(1)
val x2 = Number(1)
x1 == x2

I have the following result:

x1: Number = Number(1)

x2: Number = Number(1)

res0: Boolean = true

So x1 and x2 are the same.

However, if I drop the case modifier in the Number class definition, i.e.

abstract class Expr
class Number(n: Int) extends Expr

and then compare two instances from the Number class in the same way

val x1 = new Number(1)
val x2 = new Number(1)
x1 == x2

I have the following output:

x1: Number = Number@1175e2db

x2: Number = Number@61064425

res0: Boolean = false

It says that this time x1 and x2 are different.

Could you tell me why is this? What difference does case make in terms of comparing two instances?

Thanks, Pan

Community
  • 1
  • 1
panc
  • 817
  • 2
  • 14
  • 30
  • Sorry, I mistakenly created `val x2 = Number(2)` which should have been `val x2 = Number(1)`. I have corrected it. – panc Jan 30 '15 at 03:23

1 Answers1

11

When you define a case class in Scala, the compiler generates an equals method which checks for deep equality (i.e., the contents of the class).

From: http://www.scala-lang.org/old/node/107

For every case class the Scala compiler generates equals method which implements structural equality and a toString method.

When you drop the case keyword, you generate regular classes, and doing an == on them checks for reference (shallow) equality. Since you're comparing two unique instances of the class, they fail reference equality even though their contents are the same.

For difference between shallow and deep equality, see:
What is the difference between being shallowly and deeply equal? How is this applied to caching?

Community
  • 1
  • 1
Ayush
  • 41,754
  • 51
  • 164
  • 239
  • 2
    For precision's sake, calling `==` does not force a reference equality check, it will actually call the `equals` method that you can override to do anything you want. Reference equality is just the default implementation for normal classes, forcing a reference equality check could be done via the `eq` method. This behavior of `==` is different than in Java for example. – PermaFrost Jan 30 '15 at 09:30
  • Usually words "shallow" and "deep" are used in different sense than in this answer. Normal classes does not override equals(), and the default implementation is "referential" equality, that is, compare the references of objects themselves. Case classes compare their fields for equality, but they delegate the comparison to fields' equals() methods, which, if defined the same way, lead to deep equality, but if not, lead to shallow equality (only 1 level deep). https://en.wikipedia.org/wiki/Object_copying#Shallow_copy – Konstantin Pelepelin Apr 20 '17 at 13:06