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.r...@oracle.com> , @Alan Bateman <alan.bate...@oracle.com> , and @- <liangchenb...@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.bate...@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 <holo3...@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, <davidalayac...@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 >> >