On Wed, 4 Jan 2023 05:28:10 GMT, Nir Lisker <[email protected]> wrote:
>> John Hendrikx has updated the pull request incrementally with two additional
>> commits since the last revision:
>>
>> - Clean up expression classes repeated null checks
>> - Use instanceof with pattern matching in a few spots
>
> I took a closer look at the sorting-related classes. I think that the design
> there is not ideal. Fixing it might be out of scope for this PR. I wouldn't
> mind fixing it myself, by the way.
>
> The way the JDK treats soring on lists is with a single `sort(Comparable c)`
> method that, when receiving `null`, assumes that the elements are
> `Comparable` and throws if not. `Collections` has 2 static sorting methods
> that help enforce this condition, where the one that doesn't take a
> `Comparator` passes `null` to the one that does.
>
> JavaFX tries to emulate this. `FXCollections` has the same 2 methods for
> `ObservableList`, but one doesn't call the other. The asymmetry comes from
> `SortableList` (which doesn't live up to its name - non-sortable lists can
> also implement it). It defines a 0-argument method and a
> `Comparator`-argument method as different behaviors, instead of one calling
> the other. This is deferred to its implementations, `ObservableListWrapper`
> and `ObservableSequentialListWrapper`, which make the differentiation by,
> again, calling 2 different methods on `SortHelper`.
>
> I suggest that the argument check be made at the lowest level, like in the
> JDK (inside `Arrays` sort method). First, `FXCollections` can change to:
>
>
> public static <T extends Comparable<? super T>> void
> sort(ObservableList<T> list) {
> sort(list, null); // or Comparator.naturalOrder() instead of null
> }
>
> public static <T> void sort(ObservableList<T> list, Comparator<? super T>
> c) {
> if (list instanceof SortableList) {
> list.sort(c);
> } else {
> List<T> newContent = new ArrayList<>(list);
> newContent.sort(c);
> list.setAll(newContent);
> }
> }
>
>
> `SortableList` then removes its `sort()` method, and now it's just overriding
> `List::sort(Comparator)` without doing anything with it, so it can be removed
> too, and it's left as a marker interface for the special sorting in
> `SortHelper` (I haven't understood yet why it's better , I need to dig there
> more):
>
>
> public interface SortableList {}
>
>
> Now `ObservableListWrapper` and `ObservableSequentialListWrapper` also remove
> `sort()`, and override `List::sort(Comparator)` directly and in accordance
> with its contract, passing the (possibly `null`) comparator to `SortHelper`,
> which is akin to the JDK's `Arrays::sort` method.
>
> Now I need to look into `SortHelper` to see what it does exactly and how to
> change it. I think it doesn't need the `sort(List<T> list)` method too now
> because it doesn't really enforce that the elements are `Comparable`, it will
> naturally throw if not.
>
> ---
>
> In my opinion, this is the design flaw: `ObservableList` should have
> overridden `List`'s sort method to specify that its sorting is done as one
> change:
>
>
> public interface ObservableList<E> extends List<E>, Observable {
>
> @Override
> default void sort(Comparator<? super E> c) {
> var newContent = new ArrayList<>(this);
> newContent.sort(c);
> setAll(newContent);
> }
>
>
> Then we wouldn't need the `SortableList` marker because `FXCollections` could
> just call this method directly (like `Collections` does, which means that
> `FXCollections`'s methods are not needed anymore, though we can't remove
> them), and whichever implementation wants to do a more efficient sorting,
> like `ObservableListWrapper`, can override again.
> This will be a behavioral change, though, because the generated change events
> differ.
@nlisker I think I made all modifications requested, is there anything else
that should be done here? Do you want the sort changes to be made or an issue
be filed for it?
-------------
PR: https://git.openjdk.org/jfx/pull/972