On Wed, 14 Jun 2023 19:26:01 GMT, Kevin Rushforth <k...@openjdk.org> wrote:

>> Yeah I'm aware they want to add this, but it doesn't really invalidate my 
>> point as that syntax is terrible still.  Method references are far preferred 
>> whenever possible.
>> 
>> I stand by my point that using the observable parameter is a rare and quite 
>> advanced use case, where these API's would be intended to make it easier and 
>> safer to use method references and lambda's.
>> 
>> When dealing with multiple listeners that require the `Observable`, you are 
>> likely also dealing with adding and removing that single listener in some 
>> dynamic fashion.  Subscriptions don't work well with this as you'd need to 
>> track these, unlike `removeListener` which you can just pass the single 
>> listener reference.
>> 
>> Here's one of the only examples in JavaFX that uses the observable parameter 
>> (if you know of others, I'd be interested to see those as well):
>> 
>>         private final ChangeListener<Boolean> paneFocusListener = new 
>> ChangeListener<>() {
>>             @Override public void changed(ObservableValue<? extends Boolean> 
>> observable, Boolean oldValue, Boolean newValue) {
>>                 if (newValue) {
>>                     final ReadOnlyBooleanProperty focusedProperty = 
>> (ReadOnlyBooleanProperty) observable;
>>                     final TitledPane tp = (TitledPane) 
>> focusedProperty.getBean();
>>                     focus(accordion.getPanes().indexOf(tp));
>>                 }
>>             }
>>         };
>> 
>> And its management code:
>> 
>>         private final ListChangeListener<TitledPane> panesListener = c -> {
>>             while (c.next()) {
>>                 if (c.wasAdded()) {
>>                     for (final TitledPane tp: c.getAddedSubList()) {
>>                         tp.focusedProperty().addListener(paneFocusListener);
>>                     }
>>                 } else if (c.wasRemoved()) {
>>                     for (final TitledPane tp: c.getRemoved()) {
>>                         
>> tp.focusedProperty().removeListener(paneFocusListener);
>>                     }
>>                 }
>>             }
>>         };
>> 
>> To do this with `Subscription::unsubscribe` you'd need to track the 
>> `Subscriptions`... something like:
>> 
>>         private final Map<Property<?>, Subscription> subscriptions = new 
>> HashMap<>();
>>         private final ListChangeListener<TitledPane> panesListener = c -> {
>>             while (c.next()) {
>>                 if (c.wasAdded()) {
>>                     for (final TitledPane tp: c.getAddedSubList()) {
>>                         subscriptions.put(tp.foc...
>
> I think the three newly added methods are a good choice. I wonder if we can 
> some up with better names, though. without some verb like "add" or 
> "subscribe" in the name, the name doesn't really indicate that it is adding a 
> new listener to the observable.

I agree that the chosen names `invalidation`, `changes` and `values` are a bit 
terse.  The whole signature (without reading docs) should make it clear you are 
creating a subscription, but perhaps we can do better.  The use of 
`addListener` can be ruled out as it would conflict with the existing method 
due to having Lambda's with the same arity (the `values` listener would 
conflict with `addListener(InvalidationListener)`.  Also, an `add` method would 
probably have users expecting a corresponding `remove` method.

A few ideas listed here:

| invalidation | values | changes |
|---|---|---|
|`subscribe(Runnable)`(*)|`subscribe(Consumer)`(*)|`subscribe(BiConsumer)`(*)|
|`subscribeInvalidations(Runnable)`|`subscribeValues(Consumer)`|`subscribeChanges(BiConsumer)`|
|`invalidationsTo(Runnable)`|`valuesTo(Consumer)`|`changesTo(BiConsumer)`|

(*) May limit future listener types that have same arity, but can still be a 
good choice

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

PR Review Comment: https://git.openjdk.org/jfx/pull/1069#discussion_r1232029010

Reply via email to