Thoughts on a new method for equality on java.util.Objects?

David Alayachew davidalayachew at gmail.com
Sun Feb 11 10:10:13 UTC 2024


Hello,

Thank you for your response!

So, I had thought of that before posting this email, and mentally, I had
hand-waved away the concern by saying that there were plenty of situations
where equality would still be useful without hashing. And while I still
very much feel the same, the way you phrased your question is making me
realize that my proposal could double nicely as a foot gun.

Like you said -- Java's concept of equality is often attached to the
concept of hashing. And while the 2 are permitted to exist out of alignment
with each other, handling the asymmetric relationship is a dangerous
balancing act that is error-prone.

I fear that this method would be handing developer a foot gun. There
already exists a large number of bugs caused by misalignment between equals
and hashCode, and I see how this method would contribute to exactly that
problem. Understanding that, I myself don't feel comfortable pushing this
method forward.

That said, I do appreciate you , @Philip Race <philip.race at oracle.com> , @Alan
Bateman <Alan.Bateman at oracle.com> , and @- <liangchenblue at gmail.com> for
being helpful as I go through the process. If nothing else, this was
educational, and I now know exactly what concerns my next proposal should
keep in mind when I try again.

And I see the value of "socializing", as @Alan Bateman
<Alan.Bateman at oracle.com> put it. I had thought this idea through plenty,
but I can only see from my perspective.

Thank you all for your time and help!
David Alayachew

On Sun, Feb 11, 2024 at 3:26 AM Holo The Sage Wolf <holo3146 at gmail.com>
wrote:

> How beneficial is it to extend equality method without appropriate hashing?
>
> Specifically, given you are working in a domain specific world, e.g.
> projection of Point3D into XY with equality semantics of equalsByXY, Java
> does not know how to treat semantically equal objects as equal:
>
> var foo = new Point3D(0,0,0);
> var bar = new Point3D(0,0,1);
> var set = new HashSet<>(Arrays.asList(foo, bar));
> assert set.size() == 1 \\ assertion failure :(
>
> The idea is fine, but you need to wrap a lot of Java's Standard Library to
> respect the new semantics.
>
> I think that the idea can work nicely as a library, but not inside java.*
>
>
> On Sun, 11 Feb 2024, 07:41 David Alayachew, <davidalayachew at gmail.com>
> wrote:
>
>> Hello Core Libs Dev Team,
>>
>> I jumped the gun a bit and made a PR for this first. Alan Bateman kindly
>> informed me of my faux pas, and now I'm trying to redo things correctly.
>>
>> I am looking to add a new method to java.util.Objects to facilitate
>> equality checks, something that I hope fits well in place with the other
>> methods in this class.
>>
>> Here is my basic idea. (Special thanks to @liach for guidance in creating
>> this!)
>>
>> ```java
>> import java.util.*;
>> import java.util.function.*;
>>
>> import static java.util.Objects.*;
>>
>> public class Objects2
>> {
>>
>>    public static <T> BiPredicate<T, T> equalsBy(final List<Function<T,
>> ?>> functions)
>>    {
>>
>>       requireNonNull(functions, "Objects.equalsBy cannot execute because
>> the parameter is null!");
>>
>>       return
>>          (final T o1, final T o2) ->
>>          {
>>
>>             requireNonNull(o1, "Cannot check for equality because the
>> first object is null!");
>>             requireNonNull(o2, "Cannot check for equality because the
>> second object is null!");
>>
>>             for (final var function : functions)
>>             {
>>
>>                requireNonNull(function, "Cannot check for equality
>> because the function is null!");
>>
>>                final var r1 = function.apply(o1);
>>                final var r2 = function.apply(o2);
>>
>>                final boolean theyAreEqual = Objects.equals(r1, r2);
>>
>>                if (!theyAreEqual)
>>                {
>>
>>                   return false;
>>
>>                }
>>
>>             }
>>
>>             return true;
>>
>>          }
>>          ;
>>
>>    }
>>
>>    public static void main(final String[] args)
>>    {
>>
>>       record Point3D(int x, String y, int z) {}
>>
>>       final Point3D a = new Point3D(1, "2", 3);
>>       final Point3D b = new Point3D(1, "2", 4);
>>
>>       final BiPredicate<Point3D,Point3D> equalsByXY  =
>> equalsBy(List.of(Point3D::x, Point3D::y));
>>       final BiPredicate<Point3D,Point3D> equalsByXYZ =
>> equalsBy(List.of(Point3D::x, Point3D::y, Point3D::z));
>>
>>       System.out.println(equalsByXY.test(a, b));  //true
>>       System.out.println(equalsByXYZ.test(a, b)); //false
>>
>>    }
>>
>> }
>> ```
>>
>> The concept is simple -- I want to make it easy to create ad-hoc equals
>> methods.
>>
>> Object equality is domain-specific -- in some domains, 2 objects are
>> equal, but in another, they are not. The object's equals method is not
>> always a good spot to put this logic into, largely because we don't always
>> know what domain we are in. The object's equals method is where a good
>> default should be placed, not logic for every domain. And even if we tried,
>> it's difficult, if not impossible, to apply equality for the correct domain
>> if both objects are of the same type.
>>
>> So, for domain-specific contexts, I would like to introduce this method.
>> This method (which should be constant-foldable, thanks again for the help
>> @liach!) lets you clearly say that you are taking 2 objects and comparing
>> them by the following methods that apply to both. And due to the nature of
>> lambdas, developers are not constrained to just the getters of the object
>> in question -- any function that takes in T is fair game. This allows
>> flexibility, and lets developers keep their objects simple, thus
>> facilitating things like DOP.
>>
>> Now, perhaps this makes more sense on the BiPredicate interface instead.
>> However, since this was more equality focused, I figured Objects was a
>> better fit.
>>
>> Any thoughts?
>>
>> Thank you all for your time and help!
>> David Alayachew
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20240211/d565c6cc/attachment-0001.htm>


More information about the core-libs-dev mailing list