On Fri, 11 Aug 2023 22:03:28 GMT, John Hendrikx <jhendr...@openjdk.org> wrote:

>> Incorporates documentation review comments from #1069.
>> 
>> This PR should be kept minimal so it can be backported to JFX21; it should 
>> only contain documentation changes.
>
> John Hendrikx has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Update wording on value subscriber

I think that might be better; changing docs on `Observable` and 
`ObservableValue` is a good idea, but may take some time to get agreement on. I 
would like to also make clear in such a change when you can expect listener / 
subscribers to fire, basically documenting the undocumented rules we already 
have (invalidations fire first then changes; listeners fire in the order they 
were added, allowing vetoing (which is used in and outside of JavaFX).

The general rules would be something like:
- Observers on super types fire before observers on sub types (ie. `Observable` 
before `ObservableValue`)
- Observers added on a single type fire in the order they were added (ie. value 
subscribers, change subscribers and change listeners are not separate lists as 
they're all offered by `ObservableValue`)

I've done an attempt to update the `Observable` class documentation with all 
recent developments:


/**
 * An {@code Observable} is an entity that wraps content and allows to
 * observe the content for invalidations.
 *
 * <h2>Lazy evaluation and events</h2>
 *
 * An implementation of {@code Observable} may support lazy evaluation,
 * which means that the content is not immediately recomputed after changes, but
 * lazily the next time it is requested. All bindings and properties in
 * this library support lazy evaluation.
 * <p>
 * Implementations of this class should strive to generate as few events as
 * possible to avoid wasting too much time in event handlers. Implementations in
 * this library mark themselves as invalid when the first invalidation event
 * occurs. They do not generate anymore invalidation events until their value is
 * recomputed and valid again.
 *
 * <h2>Observing an {@code Observable}</h2>
 *
 * Observation is possible using listeners and subscribers. These are
 * interchangeable and have the same semantics:
 * <li>Observers are notified in the order they were added</li>
 * <li>When an observer is registered more than once, it will be notified more 
than once</li>
 * <li>Observers may be safely registered for different {@code Observable}s</li>
 * <p>
 * When observing an {@code Observable}, it will hold a strong reference to the 
observer which will
 * prevent it from being garbage collected as long as the {@code Observable} is 
reachable.
 * If the lifecycle of the {@code Observable} is longer than a registered 
observer, care
 * must be taken to unregister the observer after use to avoid unwanted 
retention of the
 * observer, and any other objects it may refer to, in memory (also known as a 
memory leak).
 *
 * <h2>Unregistering observers</h2>
 *
 * Unregistering observers when their use ends can be achieved in several ways:
 * <li>For listeners, call the corresponding {@code removeListener} method, 
ensuring to pass the exact same instance as was used to register it</li>
 * <li>For subscribers, call {@link Subscription#unsubscribe()} on each {@link 
Subscription}, or on a combined subscription</li>
 * <li>If the {@code Observable} is an {@code ObservableValue}, {@link 
ObservableValue#when(ObservableValue)} can be used to automatically
 *     decouple the lifecycle of the observer from the original {@code 
ObservableValue} when a condition (like visibility) holds:
 *     <pre>
 *     {@code
 *     observableValue.when(condition).subscribe(...)
 *     }</pre>
 * </li>
 * <li>For listeners, it's possible to use a weak wrapper, like {@link 
WeakInvalidationListener}, to automatically unregister the listener when it 
becomes weakly reachable</li>
 * <p>
 * Note that the use of weak listener wrappers is no longer recommended when it 
can be
 * avoided as it requires intimate knowledge of how weak references work in 
Java and how
 * they interact with the garbage collector. The timing of when a weak listener 
is
 * unregistered may be very different from the intended or expected timing. It 
can
 * depend on many external factors, including the JVM used, its version, its 
(GC) settings,
 * but also on the system type and its memory availability.
 * <li>Garbage collection may be deferred for long periods (or even 
indefinitely), resulting in weak listeners being removed much later than 
expected;
 * until such time, they will keep receiving events, and hold on to any 
referenced objects</li>
 * <li>Weak listeners may be cleaned up almost immediately, possibly resulting 
in a listener being removed if care wasn't taken
 * to reference it directly</li>
 * <li>Registering the same or a similar weak listener again may see strange 
behavior as a previous weak listener may still be present</li>
 * <p>
 * The above can lead to hard to reproduce issues that may vary from system to 
system.
 * <p>
 * It is therefore highly recommended to always remove observers which observe 
an {@code Observable}
 * that have a longer lifecycle. This can be done either manually (in a clean 
up or dispose method),
 * or automatically using a condition with {@code ObservableValue#when}.
 *
 * @see javafx.beans.value.ObservableValue
 * @see javafx.collections.ObservableList
 * @see javafx.collections.ObservableMap
 *
 *
 * @since JavaFX 2.0
 */

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

PR Comment: https://git.openjdk.org/jfx/pull/1177#issuecomment-1683728523

Reply via email to