On Fri, 15 Jul 2022 09:27:00 GMT, John Hendrikx <jhendr...@openjdk.org> wrote:

>> This PR adds a new (lazy*) property on `Node` which provides a boolean which 
>> indicates whether or not the `Node` is currently part of a `Scene`, which in 
>> turn is part of a currently showing `Window`.
>> 
>> It also adds a new fluent binding method on `ObservableValue` dubbed `when` 
>> (open for discussion, originally I had `conditionOn` here).
>> 
>> Both of these together means it becomes much easier to break strong 
>> references that prevent garbage collection between a long lived property and 
>> one that should be shorter lived. A good example is when a `Label` is bound 
>> to a long lived property:
>> 
>>      
>> label.textProperty().bind(longLivedProperty.when(label::isShowingProperty));
>> 
>> The above basically ties the life cycle of the label to the long lived 
>> property **only** when the label is currently showing.  When it is not 
>> showing, the label can be eligible for GC as the listener on 
>> `longLivedProperty` is removed when the condition provided by 
>> `label::isShowingProperty` is `false`.  A big advantage is that these 
>> listeners stop observing the long lived property **immediately** when the 
>> label is no longer showing, in contrast to weak bindings which may keep 
>> observing the long lived property (and updating the label, and triggering 
>> its listeners in turn) until the next GC comes along.
>> 
>> The issue in JBS also describes making the `Subscription` API public, but I 
>> think that might best be a separate PR.
>> 
>> Note that this PR contains a bugfix in `ObjectBinding` for which there is 
>> another open PR: https://github.com/openjdk/jfx/pull/829 -- this is because 
>> the tests for the newly added method would fail otherwise; once it has been 
>> integrated to jfx19 and then to master, I can take the fix out.
>> 
>> (*) Lazy means here that the property won't be creating any listeners unless 
>> observed itself, to avoid problems creating too many listeners on 
>> Scene/Window.
>
> John Hendrikx has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Rename showing property to shown as it is already used in subclasses

I reviewed the docs so a CSR can be submitted. Will do the implementation and 
tests reviews later. The implementation looks fine, but I need to review the 
subscription model closely.

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
258:

> 256:     /**
> 257:      * Returns an {@code ObservableValue} that holds this value whenever 
> the given
> 258:      * condition evaluates to {@code true}, otherwise holds the last 
> value when

> evaluates to

Maybe "holds"?

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
259:

> 257:      * Returns an {@code ObservableValue} that holds this value whenever 
> the given
> 258:      * condition evaluates to {@code true}, otherwise holds the last 
> value when
> 259:      * {@code condition} became {@code false}. The value is updated 
> whenever this

> became `{@code false}`

If it was `false` from the start then the observable still holds the initial 
value. Maybe "was `{@code false}`"?

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
260:

> 258:      * condition evaluates to {@code true}, otherwise holds the last 
> value when
> 259:      * {@code condition} became {@code false}. The value is updated 
> whenever this
> 260:      * {@code ObservableValue} changes, unless the condition currently 
> evaluates

Maybe it's a bit clearer to indicate when the value changes rather than when it 
doesn't:

> The value is updated whenever this `{@code ObservableValue}` changes and 
> `{@code condition}` holds `{@code true}`

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
266:

> 264:      * {@code condition} evaluates to {@code true}. This allows this 
> {@code ObservableValue}
> 265:      * and the conditional {@code ObservableValue} to be garbage 
> collected if neither is
> 266:      * otherwise strongly referenced when {@code condition} becomes 
> {@code false}.

What happens if they are GC'd and the conditional becomes `true` later?

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
269:

> 267:      * <p>
> 268:      * A currently observed binding will observe its source, which means 
> it will not be eligible
> 269:      * for garbage collection while source isn't. However, using {@code 
> when} this {@code ObservableValue}

"while source isn't" -> "while **its** source"

"However, using `{@code when}` this `{@code ObservableValue}`" -> "However, 
when using `{@code when}`, this `{@code ObservableValue}`"

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
271:

> 269:      * for garbage collection while source isn't. However, using {@code 
> when} this {@code ObservableValue}
> 270:      * can still be eligible for garbage collection when the condition 
> is {@code false} and the
> 271:      * conditional itself is also eligible for garbage collection.

Wasn't this explained in the previous paragraph?

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
274:

> 272:      * <p>
> 273:      * Returning {@code null} from the given condition is treated the 
> same as
> 274:      * returning {@code false}.

I would rephrase to use the "holds" language instead of the "return":

> `{@code condition}` holding `{@code null}` is treated the same as it holding 
> {@code false}`

But is this the behavior we want? I would consider throwing when the condition 
is not a `true` or `false` because it's a boolean condition. `orElse` can be 
used to create a condition that maps `null` to something else if the user wants 
to accept `null`s in the condition. I'm not sure if this is really a problem.

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
302:

> 300:      * ObservableValue<String> globalProperty = new 
> SimpleStringProperty("A");
> 301:      *
> 302:      * // bind label's text to a global property only when it is shown:

"a label's"

modules/javafx.base/src/main/java/javafx/beans/value/ObservableValue.java line 
302:

> 300:      * ObservableValue<String> globalProperty = new 
> SimpleStringProperty("A");
> 301:      *
> 302:      * // bind label's text to a global property only when it is shown:

I would move the comment explanation outside:


An example for binding a label's text to a global property only when it is 
shown:
...
Label label = ... ;
ObservableValue<String> globalProperty = new SimpleStringProperty("A");
label.textProperty().bind(globalProperty.when(label::isShownProperty));
...

-------------

Changes requested by nlisker (Reviewer).

PR: https://git.openjdk.org/jfx/pull/830

Reply via email to