From: Robert Klemme Date: 2013-06-18T16:19:08+09:00 Subject: Re: Comparing objects --089e0153746a4b3ce504df688719 Content-Type: text/plain; charset=ISO-8859-1 On Tue, Jun 18, 2013 at 12:11 AM, Josh Cheek wrote: > On Mon, Jun 17, 2013 at 4:25 PM, Graham Menhennitt < > graham@menhennitt.com.au> wrote: > >> On 18/06/2013 2:06 AM, Josh Cheek wrote: >> >> On Mon, Jun 17, 2013 at 10:52 AM, Thom T. wrote: >> >>> How do I compare two objects in Ruby, considering only attributes >>> values? >>> >> > I suspect that the OP is looking for something a bit more generalised. >> >> def ==(rhs) >> return false unless rhs.is_a?(self.class) >> > That comparison is moot because it is not symmetric (see article linked below). > instance_variables.each do |var| >> return false unless instance_variable_get(var) == >> rhs.instance_variable_get(var) >> end >> return true >> end >> >> Note that the first line of this can be changed according to taste: >> - as above, two objects will compare as equal if the class of the right >> hand side is the same as or a sub-class of the left hand side >> - remove it completely in which case you get "duck typing" equality (no >> relationship needed between classes of object) >> - change it to "return false unless rhs.class == lhs.class" in which case >> the two objects must be of the same class >> In the first case, a == b will not necessarily return the same as b == a. >> >> Also, note that this code allows the right hand side to have extra >> instance variables that the left hand side does not, but they can still >> compare as equal. That may or may not be desirable. If not, you need to >> test for it as well. Again, the way I've written it, a == b is not the same >> as b == a. >> >> > Perhaps, but I think this is not a good approach. > > It's too magical: > * You give up control of what constitutes equality (these kind of implicit > assumptions seem to always break down) > * You store something in a var and all of a sudden your objects aren't > showing up equal. It really sucks when making some change that doesn't > matter suddenly causes everything to break for no obvious reason. > * You can't look at the behaviour and figure out what it's doing, b/c it's > violating encapsulation. > All very good points! If this was a relational database we were talking about the primary key. This is also something we define explicitly and not accidentally. In order to not repeat myself too much I reference my blog article about the topic: http://blog.rubybestpractices.com/posts/rklemme/018-Complete_Class.html Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/ --089e0153746a4b3ce504df688719 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable



On Tue, Jun 18, 2013 at 12:11 AM, Josh Cheek <= josh.cheek@gmail.= com> wrote:
On Mon, Jun 17, 2013 at = 4:25 PM, Graham Menhennitt <graham@menhennitt.com.au>= wrote:
=20 =20 =20
On 18/06/2013 2:06 AM, Josh Cheek wrote:
On Mon, Jun 17, 2013 at 10:52 AM, Thom T. <lists@ruby-forum.com> wrote:
How do I compare two objects in Ruby, considering only attributes
values?
=A0
I suspect that the OP is looking for something a bit more generalised.

=A0=A0=A0=A0=A0=A0=A0 def =3D=3D(rhs)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return false unless rhs.is_a?(self.cl= ass)

That comparison is moot because it is not symmetric (see article l= inked below).
=A0
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 instance_variables.each do |var|
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return false unless insta= nce_variable_get(var) =3D=3D rhs.instance_variable_get(var)
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 end
=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return true
=A0=A0=A0=A0=A0=A0=A0 end

Note that the first line of this can be changed according to taste:
- as above, two objects will compare as equal if the class of the right hand side is the same as or a sub-class of the left hand side
- remove it completely in which case you get "duck typing" eq= uality (no relationship needed between classes of object)
- change it to "return false unless rhs.class =3D=3D lhs.class&quo= t; in which case the two objects must be of the same class
In the first case, a =3D=3D b will not necessarily return the same as b =3D=3D a.

Also, note that this code allows the right hand side to have extra instance variables that the left hand side does not, but they can still compare as equal. That may or may not be desirable. If not, you need to test for it as well. Again, the way I've written it, a =3D=3D b is not the same as b =3D=3D a.


Perhaps, but I t= hink this is not a good approach.

It's too mag= ical:
* You give up control of what constitutes equality (these k= ind of implicit assumptions seem to always break down)
* You store something in a var and all of a sudden your objects aren&#= 39;t showing up equal. It really sucks when making some change that doesn&#= 39;t matter suddenly causes everything to break for no obvious reason.
* You can't look at the behaviour and figure out what it's doi= ng, b/c it's violating encapsulation.

=
All very good points! =A0If this was a relational database= we were talking about the primary key. =A0This is also something we define= explicitly and not accidentally.

In order to not repeat myself too much I re= ference my blog article about the topic:

Kind regards

robert


--
reme= mber.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
--089e0153746a4b3ce504df688719--