[scala] How to implement equals method

View: New views
7 Messages — Rating Filter:   Alert me  

[scala] How to implement equals method

by Ruimo Uno :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi, I saw some code that uses pattern matching to
implement equals method. As pattern matching uses
instanceof, that method is not symmetric.

class Base(val v1: Int) {
 override def equals(that: Any) = that match {
   case other: Base => other.v1 == v1
   case _ => false
 }
// ...
}

class Sub(v1: Int, val v2: Int) extends Base(v1) {
 override def equals(that: Any) = that match {
   case other: Sub => other.v1 == v1 && other.v2 == v2
   case _ => false
 }
// ...
}

shanai@shanai-desktop:~$ scala
Welcome to Scala version 2.7.1.final (IBM J9 VM, Java 1.6.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :l test.scala
Loading test.scala...
defined class Base
defined class Sub

scala> val b = new Base(1)
b: Base = Base@71547154

scala> val s = new Sub(1, 2)
s: Sub = Sub@7d497d49

scala> b == s
res0: Boolean = true

scala> s == b
res1: Boolean = false

It breaks the contract of equals method. To make the
method symmetric, I can add getClass:

class Base(val v1: Int) {
 override def equals(that: Any) = that match {
   case other: Base => other.getClass == getClass && other.v1 == v1
   case _ => false
 }
//...
}

// As same for Sub

But it seem a bit redundant. Any body knows smarter
implementation?

Thanks,

--
Ruimo Uno
(Shisei Hanai)

Re: [scala] How to implement equals method

by Sean McDirmid :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

getClass is a common approach, though it might break down if you don't
define equality exactly along class-based lines. Scala case classes
use synthetic integer tags for equality, so the built in case class
method will ignore inheritance.

I suggest sticking with getClass, unless you have generics and type
parameters to worry about, then you have no choice to but to come up
with your own tagging scheme.

On Sun, Jul 6, 2008 at 9:34 AM, Ruimo Uno <ruimo.uno@...> wrote:

> Hi, I saw some code that uses pattern matching to
> implement equals method. As pattern matching uses
> instanceof, that method is not symmetric.
>
> class Base(val v1: Int) {
>  override def equals(that: Any) = that match {
>   case other: Base => other.v1 == v1
>   case _ => false
>  }
> // ...
> }
>
> class Sub(v1: Int, val v2: Int) extends Base(v1) {
>  override def equals(that: Any) = that match {
>   case other: Sub => other.v1 == v1 && other.v2 == v2
>   case _ => false
>  }
> // ...
> }
>
> shanai@shanai-desktop:~$ scala
> Welcome to Scala version 2.7.1.final (IBM J9 VM, Java 1.6.0).
> Type in expressions to have them evaluated.
> Type :help for more information.
>
> scala> :l test.scala
> Loading test.scala...
> defined class Base
> defined class Sub
>
> scala> val b = new Base(1)
> b: Base = Base@71547154
>
> scala> val s = new Sub(1, 2)
> s: Sub = Sub@7d497d49
>
> scala> b == s
> res0: Boolean = true
>
> scala> s == b
> res1: Boolean = false
>
> It breaks the contract of equals method. To make the
> method symmetric, I can add getClass:
>
> class Base(val v1: Int) {
>  override def equals(that: Any) = that match {
>   case other: Base => other.getClass == getClass && other.v1 == v1
>   case _ => false
>  }
> //...
> }
>
> // As same for Sub
>
> But it seem a bit redundant. Any body knows smarter
> implementation?
>
> Thanks,
>
> --
> Ruimo Uno
> (Shisei Hanai)
>

Parent Message unknown Re: [scala] How to implement equals method

by Sean McDirmid :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ah, its probably changed. Anyways, maybe tags are used for traits or
maybe that aren't used at all anymore :) You could use instanceof
tests like case classes, note that equality is no longer symmetric
when you have case classes extending other case classes, basically
because equals is overridden on a per class, not class pair basis.

Sean

On Sun, Jul 6, 2008 at 9:00 PM, Shisei Hanai <shanai@...> wrote:

> I tested the following code:
>
> case class Base
> case class Sub(i: Int) extends Base
>
> object Test {
>  def main(args: Array[String]) {
>    val b = Base()
>    val s = Sub(1)
>    System.out.println(b.equals(s))
>  }
> }
>
> Compiler emits the following code for Base.equals:
>
> public boolean equals(java.lang.Object);
>  Code:
>   Stack=2, Locals=3, Args_size=2
>   0:   aload_1
>   1:   instanceof      #8; //class java/lang/Object
>   4:   ifeq    25
>   7:   aload_0
>   8:   aload_1
>   9:   if_acmpeq       21
>   12:  aload_1
>   13:  astore_2
>   14:  aload_2
>   15:  instanceof      #46; //class Base
>   18:  ifeq    25
>   21:  iconst_1
>   22:  goto    26
>   25:  iconst_0
>   26:  ireturn
>  LineNumberTable:
>   line 1: 0
>
>  LocalVariableTable:
>   Start  Length  Slot  Name   Signature
>   0      27      0    this       LBase;
>   0      27      1    x$1       Ljava/lang/Object;
>
> Even for case classes, Scala uses instanceof for type equality. As a
> result, the Test.main prints true.
>
> shanai@shanai-laptop:/tmp$ scala Test
> true
>
> Do you mean future version of Scala? I'm using 2.7.1-final
>
> Scala compiler version 2.7.1.final -- Copyright 2002-2008, LAMP/EPFL
>
> Thanks,
>
> 2008/7/6 Sean McDirmid <sean.mcdirmid@...>:
>> getClass is a common approach, though it might break down if you don't
>> define equality exactly along class-based lines. Scala case classes
>> use synthetic integer tags for equality, so the built in case class
>> method will ignore inheritance.
>>
>> I suggest sticking with getClass, unless you have generics and type
>> parameters to worry about, then you have no choice to but to come up
>> with your own tagging scheme.
>>
>> On Sun, Jul 6, 2008 at 9:34 AM, Ruimo Uno <ruimo.uno@...> wrote:
>>> Hi, I saw some code that uses pattern matching to
>>> implement equals method. As pattern matching uses
>>> instanceof, that method is not symmetric.
>>>
>>> class Base(val v1: Int) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Base => other.v1 == v1
>>>   case _ => false
>>>  }
>>> // ...
>>> }
>>>
>>> class Sub(v1: Int, val v2: Int) extends Base(v1) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Sub => other.v1 == v1 && other.v2 == v2
>>>   case _ => false
>>>  }
>>> // ...
>>> }
>>>
>>> shanai@shanai-desktop:~$ scala
>>> Welcome to Scala version 2.7.1.final (IBM J9 VM, Java 1.6.0).
>>> Type in expressions to have them evaluated.
>>> Type :help for more information.
>>>
>>> scala> :l test.scala
>>> Loading test.scala...
>>> defined class Base
>>> defined class Sub
>>>
>>> scala> val b = new Base(1)
>>> b: Base = Base@71547154
>>>
>>> scala> val s = new Sub(1, 2)
>>> s: Sub = Sub@7d497d49
>>>
>>> scala> b == s
>>> res0: Boolean = true
>>>
>>> scala> s == b
>>> res1: Boolean = false
>>>
>>> It breaks the contract of equals method. To make the
>>> method symmetric, I can add getClass:
>>>
>>> class Base(val v1: Int) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Base => other.getClass == getClass && other.v1 == v1
>>>   case _ => false
>>>  }
>>> //...
>>> }
>>>
>>> // As same for Sub
>>>
>>> But it seem a bit redundant. Any body knows smarter
>>> implementation?
>>>
>>> Thanks,
>>>
>>> --
>>> Ruimo Uno
>>> (Shisei Hanai)
>>>
>>
>
>
>
> --
> Shisei Hanai (Ruimo Uno)
> http://www.ruimo.com/
>

Re: [scala] How to implement equals method

by Christos KK Loverdos :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

The equals method is a general pain, regardless of Scala. It's all about thinking ahead on what you want to do with your classes...



On Mon, Jul 7, 2008 at 4:06 AM, Sean McDirmid <sean.mcdirmid@...> wrote:
Ah, its probably changed. Anyways, maybe tags are used for traits or
maybe that aren't used at all anymore :) You could use instanceof
tests like case classes, note that equality is no longer symmetric
when you have case classes extending other case classes, basically
because equals is overridden on a per class, not class pair basis.

Sean

On Sun, Jul 6, 2008 at 9:00 PM, Shisei Hanai <shanai@...> wrote:
> I tested the following code:
>
> case class Base
> case class Sub(i: Int) extends Base
>
> object Test {
>  def main(args: Array[String]) {
>    val b = Base()
>    val s = Sub(1)
>    System.out.println(b.equals(s))
>  }
> }
>
> Compiler emits the following code for Base.equals:
>
> public boolean equals(java.lang.Object);
>  Code:
>   Stack=2, Locals=3, Args_size=2
>   0:   aload_1
>   1:   instanceof      #8; //class java/lang/Object
>   4:   ifeq    25
>   7:   aload_0
>   8:   aload_1
>   9:   if_acmpeq       21
>   12:  aload_1
>   13:  astore_2
>   14:  aload_2
>   15:  instanceof      #46; //class Base
>   18:  ifeq    25
>   21:  iconst_1
>   22:  goto    26
>   25:  iconst_0
>   26:  ireturn
>  LineNumberTable:
>   line 1: 0
>
>  LocalVariableTable:
>   Start  Length  Slot  Name   Signature
>   0      27      0    this       LBase;
>   0      27      1    x$1       Ljava/lang/Object;
>
> Even for case classes, Scala uses instanceof for type equality. As a
> result, the Test.main prints true.
>
> shanai@shanai-laptop:/tmp$ scala Test
> true
>
> Do you mean future version of Scala? I'm using 2.7.1-final
>
> Scala compiler version 2.7.1.final -- Copyright 2002-2008, LAMP/EPFL
>
> Thanks,
>
> 2008/7/6 Sean McDirmid <sean.mcdirmid@...>:
>> getClass is a common approach, though it might break down if you don't
>> define equality exactly along class-based lines. Scala case classes
>> use synthetic integer tags for equality, so the built in case class
>> method will ignore inheritance.
>>
>> I suggest sticking with getClass, unless you have generics and type
>> parameters to worry about, then you have no choice to but to come up
>> with your own tagging scheme.
>>
>> On Sun, Jul 6, 2008 at 9:34 AM, Ruimo Uno <ruimo.uno@...> wrote:
>>> Hi, I saw some code that uses pattern matching to
>>> implement equals method. As pattern matching uses
>>> instanceof, that method is not symmetric.
>>>
>>> class Base(val v1: Int) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Base => other.v1 == v1
>>>   case _ => false
>>>  }
>>> // ...
>>> }
>>>
>>> class Sub(v1: Int, val v2: Int) extends Base(v1) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Sub => other.v1 == v1 && other.v2 == v2
>>>   case _ => false
>>>  }
>>> // ...
>>> }
>>>
>>> shanai@shanai-desktop:~$ scala
>>> Welcome to Scala version 2.7.1.final (IBM J9 VM, Java 1.6.0).
>>> Type in expressions to have them evaluated.
>>> Type :help for more information.
>>>
>>> scala> :l test.scala
>>> Loading test.scala...
>>> defined class Base
>>> defined class Sub
>>>
>>> scala> val b = new Base(1)
>>> b: Base = Base@71547154
>>>
>>> scala> val s = new Sub(1, 2)
>>> s: Sub = Sub@7d497d49
>>>
>>> scala> b == s
>>> res0: Boolean = true
>>>
>>> scala> s == b
>>> res1: Boolean = false
>>>
>>> It breaks the contract of equals method. To make the
>>> method symmetric, I can add getClass:
>>>
>>> class Base(val v1: Int) {
>>>  override def equals(that: Any) = that match {
>>>   case other: Base => other.getClass == getClass && other.v1 == v1
>>>   case _ => false
>>>  }
>>> //...
>>> }
>>>
>>> // As same for Sub
>>>
>>> But it seem a bit redundant. Any body knows smarter
>>> implementation?
>>>
>>> Thanks,
>>>
>>> --
>>> Ruimo Uno
>>> (Shisei Hanai)
>>>
>>
>
>
>
> --
> Shisei Hanai (Ruimo Uno)
> http://www.ruimo.com/
>



--
__~O
-\ <, Christos KK Loverdos
(*)/ (*) http://ckkloverdos.com

Re: [scala] How to implement equals method

by Ruimo Uno :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I eventually realized using isComparable method shown in 'Programming
in Scala' book seems the best choice.
I'm not sure why the current Scala's generated code for the equals
method of case class does not conform to this technique, though. Maybe
for compatibility issue...

On Mon, Jul 7, 2008 at 10:06 AM, Sean McDirmid <sean.mcdirmid@...> wrote:

> Ah, its probably changed. Anyways, maybe tags are used for traits or
> maybe that aren't used at all anymore :) You could use instanceof
> tests like case classes, note that equality is no longer symmetric
> when you have case classes extending other case classes, basically
> because equals is overridden on a per class, not class pair basis.
>
> Sean
>
> On Sun, Jul 6, 2008 at 9:00 PM, Shisei Hanai <shanai@...> wrote:
>> I tested the following code:
>>
>> case class Base
>> case class Sub(i: Int) extends Base
>>
>> object Test {
>>  def main(args: Array[String]) {
>>    val b = Base()
>>    val s = Sub(1)
>>    System.out.println(b.equals(s))
>>  }
>> }
>>
>> Compiler emits the following code for Base.equals:
>>
>> public boolean equals(java.lang.Object);
>>  Code:
>>   Stack=2, Locals=3, Args_size=2
>>   0:   aload_1
>>   1:   instanceof      #8; //class java/lang/Object
>>   4:   ifeq    25
>>   7:   aload_0
>>   8:   aload_1
>>   9:   if_acmpeq       21
>>   12:  aload_1
>>   13:  astore_2
>>   14:  aload_2
>>   15:  instanceof      #46; //class Base
>>   18:  ifeq    25
>>   21:  iconst_1
>>   22:  goto    26
>>   25:  iconst_0
>>   26:  ireturn
>>  LineNumberTable:
>>   line 1: 0
>>
>>  LocalVariableTable:
>>   Start  Length  Slot  Name   Signature
>>   0      27      0    this       LBase;
>>   0      27      1    x$1       Ljava/lang/Object;
>>
>> Even for case classes, Scala uses instanceof for type equality. As a
>> result, the Test.main prints true.
>>
>> shanai@shanai-laptop:/tmp$ scala Test
>> true
>>
>> Do you mean future version of Scala? I'm using 2.7.1-final
>>
>> Scala compiler version 2.7.1.final -- Copyright 2002-2008, LAMP/EPFL
>>
>> Thanks,
>>
>> 2008/7/6 Sean McDirmid <sean.mcdirmid@...>:
>>> getClass is a common approach, though it might break down if you don't
>>> define equality exactly along class-based lines. Scala case classes
>>> use synthetic integer tags for equality, so the built in case class
>>> method will ignore inheritance.
>>>
>>> I suggest sticking with getClass, unless you have generics and type
>>> parameters to worry about, then you have no choice to but to come up
>>> with your own tagging scheme.
>>>
>>> On Sun, Jul 6, 2008 at 9:34 AM, Ruimo Uno <ruimo.uno@...> wrote:
>>>> Hi, I saw some code that uses pattern matching to
>>>> implement equals method. As pattern matching uses
>>>> instanceof, that method is not symmetric.
>>>>
>>>> class Base(val v1: Int) {
>>>>  override def equals(that: Any) = that match {
>>>>   case other: Base => other.v1 == v1
>>>>   case _ => false
>>>>  }
>>>> // ...
>>>> }
>>>>
>>>> class Sub(v1: Int, val v2: Int) extends Base(v1) {
>>>>  override def equals(that: Any) = that match {
>>>>   case other: Sub => other.v1 == v1 && other.v2 == v2
>>>>   case _ => false
>>>>  }
>>>> // ...
>>>> }
>>>>
>>>> shanai@shanai-desktop:~$ scala
>>>> Welcome to Scala version 2.7.1.final (IBM J9 VM, Java 1.6.0).
>>>> Type in expressions to have them evaluated.
>>>> Type :help for more information.
>>>>
>>>> scala> :l test.scala
>>>> Loading test.scala...
>>>> defined class Base
>>>> defined class Sub
>>>>
>>>> scala> val b = new Base(1)
>>>> b: Base = Base@71547154
>>>>
>>>> scala> val s = new Sub(1, 2)
>>>> s: Sub = Sub@7d497d49
>>>>
>>>> scala> b == s
>>>> res0: Boolean = true
>>>>
>>>> scala> s == b
>>>> res1: Boolean = false
>>>>
>>>> It breaks the contract of equals method. To make the
>>>> method symmetric, I can add getClass:
>>>>
>>>> class Base(val v1: Int) {
>>>>  override def equals(that: Any) = that match {
>>>>   case other: Base => other.getClass == getClass && other.v1 == v1
>>>>   case _ => false
>>>>  }
>>>> //...
>>>> }
>>>>
>>>> // As same for Sub
>>>>
>>>> But it seem a bit redundant. Any body knows smarter
>>>> implementation?
>>>>
>>>> Thanks,
>>>>
>>>> --
>>>> Ruimo Uno
>>>> (Shisei Hanai)
>>>>
>>>
>>
>>
>>
>> --
>> Shisei Hanai (Ruimo Uno)
>> http://www.ruimo.com/
>>
>



--
Ruimo Uno
(Shisei Hanai)

Re: [scala] How to implement equals method

by Martin Odersky :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jul 7, 2008 at 10:21 AM, Ruimo Uno <ruimo.uno@...> wrote:
> I eventually realized using isComparable method shown in 'Programming
> in Scala' book seems the best choice.
> I'm not sure why the current Scala's generated code for the equals
> method of case class does not conform to this technique, though. Maybe
> for compatibility issue...
>
Right. It would break binary compatibility, so we have to wait for the
next major release to do it.

Cheers

 -- Martin

Re: [scala] How to implement equals method

by Ruimo Uno :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I see, I'm looking forward to the future version.

Thanks,

On Tue, Jul 8, 2008 at 12:57 AM, martin odersky <martin.odersky@...> wrote:

> On Mon, Jul 7, 2008 at 10:21 AM, Ruimo Uno <ruimo.uno@...> wrote:
>> I eventually realized using isComparable method shown in 'Programming
>> in Scala' book seems the best choice.
>> I'm not sure why the current Scala's generated code for the equals
>> method of case class does not conform to this technique, though. Maybe
>> for compatibility issue...
>>
> Right. It would break binary compatibility, so we have to wait for the
> next major release to do it.
>
> Cheers
>
>  -- Martin
>



--
Ruimo Uno
(Shisei Hanai)
LightInTheBox - Buy quality products at wholesale price