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

Improve documentation for the referencing model of bindings and listeners in combination with GC

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • jfx18
    • javafx

      Binding and listener behavior in JavaFX is sometimes surprising to users without this being adequately explained in the documentation.

      For example:

           x.bind(y)

      vs
       
          y.addListener((ov, old, current) -> x.set(current));

      The above two examples function nearly identical. However, if `y` is replaced with `y.concat("!")` the symmetry breaks.

      The version using `bind` keeps working as expected, however the version using the (strong) listener stops working after a GC. The reason for this is the weak binding between `y` and `y.concat`. As `y.concat` is not strongly referenced anywhere (`y` is only weakly referencing it), `y.concat` gets GC'd.

      When looking at the documentation, neither `addListener` nor `concat` makes mention of this behavior. `concat` (and many similar functions) need to be documented at a minimum that they're using a weak listener IMHO.

      In short, when using a listener, each step of a mapped chain (y.concat("!").concat("?")) must be strongly referenced in order for it to not be accidently GC'd, while for `bind` this is not the case -- the reason is that `bind`, which only allows a single binding, can strongly refer to its only source.

      There is another source of confusion:

      When an `ObservableValue` is exposed as a returned value or is passed as a parameter, users need to guess if this value is strongly referenced or not if they intend to add a listener to it:

            public ObservableValue<String> textProperty() {
                  return textProperty;
            }

            public ObservableValue<String> quotedTextProperty() {
                  return startQuote.concat(textProperty).concat("\"");
            }

      Calling one of these methods and adding a listener to its result would behave differently depending on which method is called.

      Note that with Fluent bindings this is not the case:

            public ObservableValue<String> textProperty() {
                  return textProperty;
            }

            public ObservableValue<String> quotedTextProperty() {
                  return textProperty.map(text -> "\"" + text + "\"");
            }

      Both would behave the same when a listener is added.

      This ticket was created in response to the discussion at: https://github.com/openjdk/jfx/pull/675#issuecomment-1176975103

            nlisker Nir Lisker
            jhendrikx John Hendrikx
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: