Reputation: 1288
In Scala, I have a case class representing some data:
case class Foo( val start : Int, val end : Int )
and I often use the copy method.
However, I've now reached the point where I'd like to add an extra member as an identifier, because I want the following equality behaviour:
case class NewFoo( val id : Int, val start : Int, val end : Int )
{
override def equals( any : Any ) = any match
{
case other : NewFoo => id == other.id
case _ => false
}
}
However, I'd now like to prevent the user changing the id
when they copy a NewFoo
instance, thus, once a NewFoo
is created, its data can change, but its id
will always remain the same.
Is this possible with case classes? I suspect not, since it's not really what they're designed for. On the other hand, a definition I've read of case classes is that they are "plain and immutable data-holding objects that should exclusively depend on their constructor arguments", a definition which doesn't seem to be broken by my use case.
If a case class is inappropriate, is there a way I can replicate the functionality of a one, particularly the copy method, without having an explicit case class? I'm not using pattern matching.
Upvotes: 0
Views: 110
Reputation: 38045
Yes, you could implement copy
method manually like this:
sealed class NewFoo(val id: Int, val start: Int, val end: Int) {
def copy(start: Int = start, end: Int = end) = new NewFoo(id, start, end)
override def equals(any: Any) = any match {
case other : NewFoo => id == other.id
case _ => false
}
// don't forget to override `hashCode` with `equals`
override def hashCode() = id.hashCode()
}
Note that you should also override hashCode
with equals
.
You could also make your class sealed
to avoid problems with this equals
implementation.
See also Programming in Scala/Object Equality.
You could also save pattern matching and instance creation without new
(NewFoo(0, 0, 0)
) with this companion object implementation:
object NewFoo {
def apply(id: Int, start: Int, end: Int) = new NewFoo(id, start, end)
def unapply(f: NewFoo): Option[(Int, Int, Int)] = Some((f.id, f.start, f.end))
}
Upvotes: 4