Thoughts on a new method for equality on java.util.Objects?
David Alayachew
davidalayachew at gmail.com
Wed Feb 14 23:36:32 UTC 2024
Thank you to Stuart, Michel, and Joe for taking care of closing my
enhancement and adding helpful comments, I appreciate it!
On Sun, Feb 11, 2024, 5:13 AM David Alayachew <davidalayachew at gmail.com>
wrote:
> Since I am abandoning this idea, could someone close my JBS ticket?
>
> And please link this message in the core-libs-dev archives as the close
> reason -- I fear the potential for misuse, as mentioned in previous emails
> on this thread.
>
> https://bugs.openjdk.org/browse/JDK-8324718
>
>
> On Sun, Feb 11, 2024 at 5:10 AM David Alayachew <davidalayachew at gmail.com>
> wrote:
>
>> 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/20240214/039fd53a/attachment-0001.htm>
More information about the core-libs-dev
mailing list