From: Lew on
Lew wrote:
>>> This method will appear to work if passed a 'Foo' argument because the
>>> 'Foo' argument matches more specifically than the 'Object' argument to
>>> the other 'equals()' method in the class, but it will fail in general
>>> when clients pass an 'Object' argument and bypass the specific overload,
>>> getting the parent-class version instead.
>

Simon Brooke wrote:
>> Sorry, why is this a mistake? If a 'Bar' argument is passed, equals must
>> return false anyway. Does it matter which implementation of equals is
>> invoked?
>

Eric Sosman <esos...(a)ieee-dot-org.invalid> wrote:
>      The second sentence is often true, even "usually" true, but
> not universally true.  It sometimes makes sense for the equals()
> of one class to return true when handed an instance of a different
> class.  For example, consider the equals() contract of Set:
>

If 'equals(Object)' is not overridden, then it likely returns 'false'
even for an argument where 'equals(Foo)' would return 'true' if it
were invoked on the '(Foo)' cast of that instance. Programs usually
invoke 'equals(Object)', not 'equals(Foo)', so you get results you
don't expect.

--
Lew

From: ilan on
Lew <lew(a)lewscanon.com> writes:

> Lew wrote:
>>> Your method overload question is quite important, actually.  It's a
>>> common mistake to overload 'equals()' when the intent is to override,
>>> e.g.,
>>>
>>>  public class Foo
>>>  {
>>>   ...
>>>    public boolean equals( Foo other )
>>>    {
>>>     ...
>>>    }
>>>  }
>>>
>>> This method will appear to work if passed a 'Foo' argument because the
>>> 'Foo' argument matches more specifically than the 'Object' argument to
>>> the other 'equals()' method in the class, but it will fail in general
>>> when clients pass an 'Object' argument and bypass the specific overload,
>>> getting the parent-class version instead.
>>
>
> Simon Brooke wrote:
>> Sorry, why is this a mistake? If a 'Bar' argument is passed, equals must
>> return false anyway. Does it matter which implementation of equals is
>> invoked?
>>
>
> Yes. As I already stated in my post, it will fail in the general case
> when clients invoke it with an 'Object' argument. You will then get
> the non-overridden 'equals(Object)' method from the parent class,
> which typically provides object identity comparison rather than value
> comparison, or else value comparison on the wrong fields.
>
>> I can see how this might matter for other methods with different
>> semantics, but why equals, particularly?
>>
>
> The parent 'equals()' method typically is one of those "other methods
> with different semantics". The semantics of 'equals(Object)' will
> differ from that of 'equals(Foo)' without special care, i.e., an
> override of the former that invokes the latter.
>
> 'equals()' is typically called with an 'Object' argument, and
> therefore the overload will not be invoked. Things like collections
> depend on the method to have an override. No override yields
> undesired behavior.
>

Hmm.. So it should rather be?

public class Foo
{
...
public boolean equals( Object other )
{
...
}
}

Thanks! I just learnt something.

--
ilAn



From: Lew on
Lew writes:
>> The parent 'equals()' method typically is one of those "other methods
>> with different semantics".  The semantics of 'equals(Object)' will
>> differ from that of 'equals(Foo)' without special care, i.e., an
>> override of the former that invokes the latter.
>>
>> 'equals()' is typically called with an 'Object' argument, and
>> therefore the overload will not be invoked.  Things like collections
>> depend on the method to have an override.  No override yields
>> undesired behavior.
>

ilan wrote:
> Hmm.. So it should rather be?
>
>  public class Foo
>  {
>   ...

Use @Override here

>    public boolean equals( Object other )
>    {
>     ...
>    }
>  }
>

The answer to your question depends on whether you want an override or
an overload. In the case of 'equals()' you want an override, or both.

For code that depends on an override, as with 'java.util.Set' and its
use of 'equals()', there must be such an override to give the expected
results.

--
Lew
From: Simon Brooke on
On Mon, 14 Jun 2010 11:38:41 -0700, Lew wrote:

> If 'equals(Object)' is not overridden, then it likely returns 'false'
> even for an argument where 'equals(Foo)' would return 'true' if it were
> invoked on the '(Foo)' cast of that instance. Programs usually invoke
> 'equals(Object)', not 'equals(Foo)', so you get results you don't
> expect.

OK, this is because selector-method resolution is done at compile time,
not at run time as it would be in CLOS and in some other object oriented
languages... yes?

What you're saying is if I do

Foo foo = new Foo();
Foo bar = foo;

assert foo.equals( bar);

will in this example invoke the variant of equals declared on class Foo
with the signature equals( Foo f), but

Foo foo = new Foo();
Object bar = foo;

assert foo.equals( bar);

will invoke some more generic variant of equals declared on Foo or some
superclass of Foo with the signature equals( Object o).

Have I understood you right?


--

;; Semper in faecibus sumus, sole profundam variat

From: Lew on
Lew wrote:
>> If 'equals(Object)' is not overridden, then it likely returns 'false'
>> even for an argument where 'equals(Foo)' would return 'true' if it were
>> invoked on the '(Foo)' cast of that instance.  Programs usually invoke
>> 'equals(Object)', not 'equals(Foo)', so you get results you don't
>> expect.
>

Simon Brooke <stillyet+n...(a)googlemail.com> wrote:
> OK, this is because selector-method resolution is done at compile time,
> not at run time as it would be in CLOS and in some other object oriented
> languages... yes?
>

I don't know anything about CLOS. It's not relevant anyway, nor are
those other languages.

> What you're saying is if I do
>
>         Foo foo = new Foo();
>         Foo bar = foo;
>
>         assert foo.equals( bar);
>
> will in this example invoke the variant of equals declared on class Foo
> with the signature equals( Foo f), but
>
>         Foo foo = new Foo();
>         Object bar = foo;
>
>         assert foo.equals( bar);
>
> will invoke some more generic variant of equals declared on Foo or some
> superclass of Foo with the signature equals( Object o).
>
> Have I understood you right?
>

Yes, barring the confusion with the Java-specific meaning of
"generic".

See the JLS as mentioned upthread:
<http://java.sun.com/docs/books/jls/third_edition/html/
expressions.html#292575>

--
Lew