Question: While assisting a student with a university project, we worked on a Java exercise provided by the university which defined a class for an address with the fields:

```
number
street
city
zipcode

```

And it specified that the equals logic should return true if the number and zip code match.

I was once taught that the equals method should only be doing an exact comparison between the objects (after checking the pointer), which makes some sense to me, but contradicts with the task they were given.

I can see why you would want to override the logic so that you can use things like `list.contains()` with your partial matching but I'm wondering if this is considered kosher, and if not why not?

Answer: 
Although many answers were given, my opinion still isn't present.

> 
> I was once taught that the equals method should only be doing an exact comparison between the objects
> 
> 
> 

Apart from what rules say, this definition is what people assume from their intiution when they talk about **equality**. Some answers say equality depends on context. They are right in a sense that objects can be equal even if not all of their fields match. But the common understanding of "is equal" should not be redefined too much.

Back to the topic, to me an address equal to another if it points to the same location.

In Germany there can be different specifications of a city, for example if a suburb is named. Then the city of an address in suburb SUB can be given as "Main city" only or "Main city, SUB" oder even only "SUB". Because giving the main city name is ok, all street names in a city and all its assigned suburbs must be unique.

Here the zip code is enough to tell the city, even if the city name varies.  

But leaving the street is NOT unique, unless the zip code also points to one well known street, which it usually doesn't.  

So it is not intuitive to consider two addresses equal if they can point to different locations whose difference consists of the ignored fields.

If there is a use case only requiring some but all fields, then the compare method doing so should be named appropriately. There is only one "is equal" method that should not be secretly turned into "is equal for only one special use case - but noone can see that".

That means, for the explained reasons I'd say...

> 
> but I'm wondering if this is considered kosher
> 
> 
> 

Without knowledge if you accidentally are in a location where street names don't matter: no it isn't.  

If you want to program something not only used in such a location: no it isn't.  

If you want to give students a feeling of doing things right and keeping code comprehensible and logical: no it isn't.
Equality is subtle to get right and its importance is deceptively far-reaching. Especially in languages where implementing an equality operator suddenly means that your object is supposed to play nice with sets and maps.

In the overwhelming majority of cases, equality should be identity, meaning an object is equal to another if and only if it *is* the same piece of memory with the same address. The identity relation always respects all the conditions for a proper equality relation: reflexivity, transitivity etc. Identity is also the fastest way to compare any two things, as you merely compare the two pointers. Respecting the equivalence relation contracts is the single most important thing about any implementation of equality as failure to do so translates into bugs that are notoriously hard to diagnose.

The second way of implementing equals is to compare if the types match then compare every "owned" field of the object. This often ends up recursing far into the details of every object. If your object goes into data structures which call equals, equals will probably be what the data structure spends most of its time doing if you use this approach. There are other problems:

* if the object changes, then the result of its comparison with other objects also changes, which breaks all sorts of assumptions that standard classes make about equality;
* if your object is in a class/interface hierarchy, the only sane way to compare two objects in that hierarchy is if their concrete types match exactly (see Joshua Bloch's excellent *Effective Java* book for more details on this);
* if you try to make the equality relationship very strict by including as many fields as possible, eventually you'll end up in a situation where your equality does not correspond to a business logic of "sameness".

The third way would be to select only the fields which are relevant for the business logic and ignore the rest. The likelihood of this approach being broken is arbitrarily close to 1. The first reason as mentioned by others is that a comparison that makes sense in *one* context doesn't necessarily make sense in *all* contexts. The language asks that you define *one* form equality though, so it better work in all contexts. For addresses, such a comparison logic simply doesn't exist. You can have specialized "those two addresses *look* identical" methods but you shouldn't risk any such method being the language-backed Only True Way To Compare as that will inevitably confuse readers.

I would also recommend taking a look at Falsehoods programmers believe about addresses: <https://www.mjt.me.uk/posts/falsehoods-programmers-believe-about-addresses/> it's a fun read and might help you avoid some pitfalls.