41

Is it possible to ignore a field of a case class in the equals/haschode method of the case class?

My use case is that I have a field that is essentially metadata for rest of the data in the class.

snv
  • 133
  • 1
  • 11
ChucK
  • 2,114
  • 1
  • 18
  • 20

4 Answers4

95

Only parameters in the first parameter section are considered for equality and hashing.

scala> case class Foo(a: Int)(b: Int)
defined class Foo

scala> Foo(0)(0) == Foo(0)(1)
res0: Boolean = true

scala> Seq(0, 1).map(Foo(0)(_).hashCode)
res1: Seq[Int] = List(-1669410282, -1669410282)

UPDATE

To expose b as a field:

scala> case class Foo(a: Int)(val b: Int)
defined class Foo

scala> Foo(0)(1).b
res3: Int = 1
retronym
  • 54,768
  • 12
  • 155
  • 168
7
scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Foo private(x: Int, y: Int) {
  def fieldToIgnore: Int = 0
}

object Foo {
  def apply(x: Int, y: Int, f: Int): Foo = new Foo(x, y) {
    override lazy val fieldToIgnore: Int = f
  }
}

// Exiting paste mode, now interpreting.

defined class Foo
defined module Foo

scala> val f1 = Foo(2, 3, 11)
f1: Foo = Foo(2,3)

scala> val f2 = Foo(2, 3, 5)
f2: Foo = Foo(2,3)

scala> f1 == f2
res45: Boolean = true

scala> f1.## == f2.##
res46: Boolean = true

You may override .toString if necessary.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
2

You can override the equals and hasCode methods in a case class

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Person( val name:String, val addr:String) {
  override def equals( arg:Any) = arg match {
    case Person(s, _) => s == name
    case _ => false
  }
  override def hashCode() = name.hashCode
}

// Exiting paste mode, now interpreting.

scala> Person("Andy", "") == Person("Andy", "XXX")
res2: Boolean = true

scala> Person("Andy", "") == Person("Bob", "XXX")
res3: Boolean = false
Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
andy
  • 1,695
  • 1
  • 9
  • 7
  • 2
    Not a very attractive option as [`.equals` is hard to get right](http://www.artima.com/lejava/articles/equality.html), and `.equals` and `.hashCode` together make for a lot of boilerplate. – missingfaktor Apr 29 '12 at 17:07
  • agree that equal/hashCode overrighting is error prone (as in java), just looks at sample code for an example. However all other methods, apply/unapply/toString/etc will be auto generated and will work as before. – andy Apr 29 '12 at 17:48
  • I'd say it's easy to get wrong, rather than hard to get right, if that makes any sense :) Have updated to something more correct – Luigi Plinge Apr 29 '12 at 17:52
0

If you override toString in the base class it will not be overridden by the derived case classes. Here is an example:

sealed abstract class C {
  val x: Int
  override def equals(other: Any) = true
}

case class X(override val x: Int) extends C

case class Y(override val x: Int, y: Int) extends C

Than we you test:

scala> X(3) == X(4)
res2: Boolean = true

scala> X(3) == X(3)
res3: Boolean = true

scala> X(3) == Y(2,5)
res4: Boolean = true
Calin-Andrei Burloiu
  • 1,481
  • 2
  • 13
  • 25