Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8251467

equals/hashCode on lambda expressions

XMLWordPrintable

    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      Equality on capturing lambda expressions is currently relies on the identity of the generated object implementing the SAM interface.
      So if we have this:
        class Example {
          private int x;
          public IntSupplier s() {
            return () -> x;
          }
        }
        var e = new Example();
        var s1 = e.s();
        var s2 = e.s();

      then s1.equals(s2) will be false, despite the two IntSupplier does the same thing: gets the x field from object "e". It would be much more useful if it returned true.

      I understand that proving that two functions compute the same result is impossible, but it could be approximated by comparing the captured variables and function object's type (which is different per call site). The equality semantics on the captured variables would be same as Objects::equals, and a generated hashCode method would also hash all the captured variables.

      I can provide a patch for InnerClassLambdaMetafactory that generates the equals and hashCode methods.


      Some real use case:

      I'm trying to create an UI framework, mainly inspired by Flutter.
      If we have this code:

        interface Widget { ... }
        record Label(String text) implements Widget {}
        record Button(String text, Runnable onClick) implements Widget {}
        record Column(List<Widget> children) implements Widget {}

        class App {

          private int i;

          Widget buildState() {
              return new Column(List.of(
                  new Label("Some text"),
                  new Button("Increment", () -> i++)
              ));
          }
        }

        var app = new App();
       
      then calling app.buildState().equals(v.buildState()) twice will produce two objects that aren't equal according to their equals method. If the instances were equal, it wouldn't be required to rebuild the layout and other associated resources.

      All objects in this hierarchy provide a proper equals implementation except the Runnable lambda expression that is the click handler of the button. But it is fairly obvious that if we call buildState() object twice, the lambda expression () -> i++ means the same thing: increments the i field of the App instance. This equality can be known by checking that the captured variables are equal. In this case, there is only one captured variable: the "this" instance of the App class. Because it's the same App instance in two subsequent buildState invocations, the equals of the lambda expression should return true when invoked on the two instance.


            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: