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