JDK-8311845 : Clarify reversed() default methods' implementation requirements
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 21,22
  • Submitted: 2023-07-11
  • Updated: 2023-07-12
  • Resolved: 2023-07-12
Related Reports
CSR :  
Description
Summary
-------

Clarify the implementation requirements (`@implSpec` sections) of the specifications of the `reversed`
methods of `Deque`, `List`, `SortedMap`, and `SortedSet`. This request is for JDK 21 and 22.

Problem
-------

The current implementation requirements merely say that the returned reverse-ordered view delegates
its operations to the backing collection. This seems to imply that calling `foo` on the view results in a call
to `foo` on the underlying collection. This isn't correct, of course (since the view is reversed, after all) but
it needs to be clarified.


Solution
--------

The obvious revision is to specify that a call to a method on the view results in a call to the appropriate
method of the backing collection, but with the opposite orientation. This is true, but only for some methods.
For example, a call to `getFirst` on the view results in a call to `getLast` on the backing collection. However,
this isn't true for all methods. For example, calling `reversed` on the view simply returns the backing
collection. This ought to be specified.

Other methods, however, cannot be specified so simply. For example, consider `addAll`. This takes all
the elements from its argument collection, in encounter order, and adds them at the end of the encounter
order of the receiver. If called on a reversed view, it needs to take the elements from the argument collection
in *reverse encounter order* and add them at the *front* of the backing collection. There are many different
ways to do this, and we don't want to specify any particular way. This is true of many of the complex
collection operations, such as `spliterator`. For these operations, we require only that the default
implementation result in calls to public methods on the backing collection, but we also state that the
exact behaviors in calling those public methods is unspecified.

Specification
-------------

Deque.reversed() --


          * @implSpec
    -     * The implementation in this interface returns an instance of a reverse-ordered
    -     * Deque that delegates its operations to this Deque.
    +     * The implementation in this interface returns a reverse-ordered Deque
    +     * view. The {@code reversed()} method of the view returns a reference
    +     * to this Deque. Other operations on the view are implemented via calls to
    +     * public methods on this Deque. The exact relationship between calls on the
    +     * view and calls on this Deque is unspecified. However, order-sensitive
    +     * operations generally delegate to the appropriate method with the opposite
    +     * orientation. For example, calling {@code getFirst} on the view results in
    +     * a call to {@code getLast} on this Deque.
          *
          * @return a reverse-ordered view of this collection, as a {@code Deque}
          * @since 21


List.reversed() --


          * @implSpec
    -     * The implementation in this interface returns an instance of a reverse-ordered
    -     * List that delegates its operations to this List.
    +     * The implementation in this interface returns a reverse-ordered List
    +     * view. The {@code reversed()} method of the view returns a reference
    +     * to this List. Other operations on the view are implemented via calls to
    +     * public methods on this List. The exact relationship between calls on the
    +     * view and calls on this List is unspecified. However, order-sensitive
    +     * operations generally delegate to the appropriate method with the opposite
    +     * orientation. For example, calling {@code getFirst} on the view results in
    +     * a call to {@code getLast} on this List.
          *
          * @return a reverse-ordered view of this collection, as a {@code List}
          * @since 21


SortedMap.reversed() --

          * @implSpec
    -     * The implementation in this interface returns an instance of a reverse-ordered
    -     * SortedMap that delegates its operations to this SortedMap.
    +     * The implementation in this interface returns a reverse-ordered SortedMap
    +     * view. The {@code reversed()} method of the view returns a reference
    +     * to this SortedMap. Other operations on the view are implemented via calls to
    +     * public methods on this SortedMap. The exact relationship between calls on the
    +     * view and calls on this SortedMap is unspecified. However, order-sensitive
    +     * operations generally delegate to the appropriate method with the opposite
    +     * orientation. For example, calling {@code firstEntry} on the view results in
    +     * a call to {@code lastEntry} on this SortedMap.
          *
          * @return a reverse-ordered view of this map, as a {@code SortedMap}
          * @since 21


SortedSet.reversed() --


          * @implSpec
    -     * The implementation in this interface returns an instance of a reverse-ordered
    -     * SortedSet that delegates its operations to this SortedSet.
    +     * The implementation in this interface returns a reverse-ordered SortedSet
    +     * view. The {@code reversed()} method of the view returns a reference
    +     * to this SortedSet. Other operations on the view are implemented via calls to
    +     * public methods on this SortedSet. The exact relationship between calls on the
    +     * view and calls on this SortedSet is unspecified. However, order-sensitive
    +     * operations generally delegate to the appropriate method with the opposite
    +     * orientation. For example, calling {@code getFirst} on the view results in
    +     * a call to {@code getLast} on this SortedSet.
          *
          * @return a reverse-ordered view of this collection, as a {@code SortedSet}
          * @since 21



Comments
Moving to Approved.
12-07-2023

> By "implementation specific public methods" I think you mean something like ArrayList.trimToSize or ArrayList.ensureCapacity. These are public methods on ArrayList but they don't appear on List. Correct > Thinking about this further, the requirement is really that, given an arbitrary List, the reversed() method's default implementation must be able to provide a reversed view using only public methods of List That makes sense. Thank you for the clarification.
11-07-2023

Interesting. By "implementation specific public methods" I think you mean something like `ArrayList.trimToSize` or `ArrayList.ensureCapacity`. These are public methods on `ArrayList` but they don't appear on `List`. It doesn't explicitly disallow using things like the `ArrayList` methods though. To use the `ArrayList` methods, the default implementation of `List.reversed` would have to do an `instanceof` and downcast or pattern match and then call the method. It's not outside the realm of possibility, but then again I can't think of any good reason for a default method to do that. On the other hand, I don't see any harm that could come from such an implementation. (In fact I think there probably are some default methods in the system that use private interfaces, so maybe I haven't thought hard enough about this.) Thinking about this further, the requirement is really that, given an *arbitrary* `List`, the `reversed()` method's default implementation must *be able to provide* a reversed view using only public methods of `List` (respectively, `Deque`, `SortedMap`, and `SortedSet`). I think it says that. If the default implementation has special cases for other things that it knows about (such as `ArrayList`) that's ok as long as the main API contract is fulfilled, and there's no reason to disallow such behavior.
11-07-2023

Hello Stuart, > For these operations, we require only that the default implementation result in calls to public methods on the backing collection, but we also state that the exact behaviors in calling those public methods is unspecified. I'm guessing that the expectation is that these public methods are the public methods/APIs on the corresponding interface (List, Deque, SortedSet, SortedMap) and not any (implementation specific) public method on the implementation class? If so, then is there any better terminology to convey that in the `implSpec` instead of the proposed: > Other operations on the view are implemented via calls to public methods on this List.
11-07-2023