[External] : Re: ReversibleCollection proposal
Stuart Marks
stuart.marks at oracle.com
Wed May 12 05:27:51 UTC 2021
>> I'm certain that uses of RC/RS will be rare in the beginning, because they will
>> be
>> new, and people won't be familar with them. And then there will the people who
>> say
>> "I can't use them because I'm stuck on JDK 11 / 8 / 7 / 6 ...." It was the same
>> thing with lambdas and streams in Java 8, with List.of() etc in Java 9, records
>> in
>> Java 16, etc. This wasn't an argument not to add them, and it isn't an argument
>> not
>> to add RC/RS.
>
> All the changes you are listing here are "client side" changes, the ones that can be adopted quickly because they do not require to change the API side of any libraries.
> ReversibleCollection is an API side change, like generics is, those changes have a far higher cost because you have to wait your library dependencies to be updated.
> On the Valhalla list, we have discussed several times about how to alleviate those API side change cost using automatic bridging or methods forwarding, even for Valhalla, we are currently moving in a state where those mechanisms are not needed.
This isn't an argument against RC/RS. Application code can find uses for the new
APIs, e.g. getFirst and addLast on List, or more ordering flexibility on
LinkedHashSet, on day one. Applications' internal APIs can also benefit on day one.
Certainly libraries will have to wait for their clients to catch up to later JDKs.
This has *always* been the case, even for library internals (such as use of lambdas
or APIs introduced in newer JDKs) because libraries need to be compiled for the
lowest version of the JDK their clients support. For example, you can't use
List.of() in a library -- even internally -- if your clients are still on JDK 8.
There are no new issues here.
> The abstraction already exists but it's not defined in term of interface because it's an implementation decision and those are cleanly separated in the current Collection design.
>
> Let take a step back, the collection API defines basic data structure operations in term of interfaces like List, Deque, Set, etc those interfaces are decoupled from implementation capabilities like mutable, nullable, ordered and checked.
>
> Depending on the implementation capabilities, the interfaces method implementation may throw an exception, non-mutable implementations use UnsupportedOperationException, non-nullable implementations use NPE and checked implementations use CCE.
>
> So what is missing is methods on Collection interfaces that require the collection implementation to be ordered like descendingList(), getFirst(), etc.
> Those methods that may throw a specific exception if the implementation is not ordered, not UnsupportedOperationException but a new one like NotOrderedException.
>
> So to answer to your question about LinkedHashSet, the reverse-ordered LinkedHashSet is a Set with a method descendingSet() that do not throw NotOrderedException like any Set with an order.
>
> To summarize, if we introduce ReversibleCollection, we should also introduce ImmutableCollection, NonNullableCollection and CheckedCollection.
> I think it's better to consider the fact that being ordered as a capability (hint: this is already what the Spliterator API does) and not as a specific interface.
This discussion, and your ensuing proposal to add a bunch of throwing default
methods to Collection, is based on a flawed premise. That premise is that there is a
fundamental distinction between "data structure operations" which must be embodied
as types, and "implementation capabilities" which must manifest at runtime either by
allowing the operation or by throwing an exception.
But this distinction isn't fundamental. In what way is being ordered not a "basic
data structure" issue? In what way is indexed access (as for List) not an
"implementation capability"? Really, these are two different aspects of the same
thing. Over time, new "data structure operations" and new "implementation
capabilities" have been added to the collections framework. Some of them were
embodied as types, and some were not. Which ones were embodied as types was the
result of design decisions that considered a bunch of tradeoffs.
What you're attempting to do is to declare absolutes. This drives you to one of two
extremes, which is either 1) to never add new types and to always add
possibly-throwing operations to existing types (which seems to be what you're
describing as an alternative); or 2) to claim that everything needs to be manifested
as a new type (giving rise to your straw-man argument that we should also have
ImmutableCollection, NonNullableCollection, CheckedCollection, etc.). The argument
seems to be that we wouldn't want to add all those other types, so we mustn't add
ReversibleCollection either. No.
In summary, I reject the premise that adding ReversibleCollection implies that a
bunch of other types also need to be added, so I don't accept this line of reasoning
as an argument against ReversibleCollection.
s'marks
More information about the core-libs-dev
mailing list