Hi Rémi

The discussion "new types? or new default methods?" is indeed a valid one. In 
fact, I think this choice has already been made once in favor of a default 
method, when adding `List::sort` was chosen over adding `SortedList` (though I 
imagine that choice was a no-brainer).

In this case I prefer adding new types though, so I wanted to share my take on 
this.

In the following diagram (see [1] in case it got mangled), I've tried to 
arrange all relevant Collection types by their defining characteristics:

|- Collection 
---------------------------------------------------------------------------------------------------------------|
|unordered    ordered                                   sorted           
distinct    distinct & ordered    distinct & sorted |
|                                                                        Set    
                                             |
|             Queue = (get|remove)First + addLast       PriorityQueue           
                                             |
|             Stack = (add|get|remove)Last                                      
                                             |
|             Deque = Queue + Stack + addFirst                                  
     LinkedHashSet         SortedSet         |
|             List = Deque + (add|get|remove)Indexed    List::sort              
                           NavigableSet      |
|----------------------------------------------------------------------------------------------------------------------------|

As I see it, there are a couple of issues with this:
* conceptually, every List is a Deque, but List doesn't extend Deque. If it 
would, all uses of List (e.g. as a parameter type in APIs) where the indexed 
access isn't required could be replaced with Deque instead. Or e.g. when you 
need to take a stack as argument: currently Deque is the recommended parameter 
type, but that means you can't just pass a List to the method as-is. With RC, 
you'd be able to use that as parameter type and pass both Deque and List.
* LinkedHashSet and SortedSet lack a common ancestor which asserts "this is an 
ordered set". So when defining an API, I'm forced to choose between SortedSet, 
which is more specific than I want, or List, which is more generic than I want 
(usually I go with SortedSet, because enforcing something through Javadoc isn't 
very reliable (cf. Collectors::toList: even though the spec clearly says the 
result might not be modifiable, people tend to simply assume it is)).

Now with RC/RS these issues would be solved, where RC is ~ Deque + reversed, 
and RS ~ Deque + distinct + reversed. In terms of the diagram, they group 
together a bunch of closely-related Collection types (see [1] if needed):

|- Collection 
---------------------------------------------------------------------------------------------------------------|
|unordered    ordered                                   sorted           
distinct    distinct & ordered    distinct & sorted |
|                                                                        Set    
                                             |
|             Queue = (get|remove)First + addLast       PriorityQueue           
                                             |
|             Stack = (add|get|remove)Last                                      
                                             |
|            |- ReversibleCollection -----------------------------------|       
    |- ReversibleSet -----------------------||
|            |Deque = Queue + Stack + addFirst                          |       
    |LinkedHashSet         SortedSet        ||
|            |List = Deque + (add|get|remove)Indexed    List::sort      |       
    |                      NavigableSet     ||
|            |----------------------------------------------------------|       
    |---------------------------------------||
|----------------------------------------------------------------------------------------------------------------------------|

On Wednesday, May 12, 2021 13:22 CEST, fo...@univ-mlv.fr wrote:

> First, i think we have overlooked ReversibleMap, if you have a LinkedHashMap, 
> the keySet should be a ReversibleSet.

I'm not sure what you meant, but the PR already defines `LinkedHashMap::keySet` 
as `public ReversibleSet<K> keySet()`.

> Again, we have seen that introducing those interfaces
> - is not source backward compatible thus it will be painful for some of our 
> users,
>   I believe NavigableSet/NavigableMap did not have that issue because only 
> one existing implementation per interface was retrofitted to implement those 
> interfaces, TreeSet for NavigableSet and TreeMap for NavigableMap.
>   ConcurrentSkipListSet/ConcurrentSkipListMap were added at the same time, so 
> there was no existing code doing a lub (lowest upper bound) between TreeSet 
> and ConcurrentSkipListSet.
>   Here, they are a lot of implementations that will implement be retrofitted 
> to ReversibleCollection, ReversibleSet and ReversibleMap.

As far as I understand, both options might cause source incompatibilities, but 
I assume you estimate the actual impact of adding default methods to be (much) 
smaller?

> - people will have to wait a theoretically infinite time before being to 
> introduce a public method that takes a ReversibleCollection, ReversibleSet 
> and ReversibleMap to their library, because it requires
>   all existing implementations of collection with an order to be retrofitted 
> to implement those interfaces.

I think I'm missing something here. I just did an experiment to convince myself 
that the set of interfaces a class implements isn't hard-wired in its class 
file. In other words, that any custom List/Deque/SortedSet/... implementation 
would be seen as implementing RC/RS without having to recompile it (that, or my 
experiment was flawed somehow, of course). So am I correct that your concerns 
are only about custom collections that implement Collection directly? If so, if 
I'd introduce a public method in my library today, I'd have to declare the 
parameter as Collection in order for custom collections to be able to use it. 
So in the future, I could either introduce an overloaded the method (one with a 
Collection parameter & one with a ReversibleCollection), or I could expect 
clients to do `List::copyOf`... right? I'd appreciate it if you could elaborate 
on this point, because I don't understand the concern yet.

> - adding any new interfaces has a real cognitive cost, the collection API is 
> supposed to be simple, does being reversible really worth such new weight.

I believe this is subjective, but to me the new interfaces are like "the 
missing piece" of the Collections API puzzle. I believe their value is also in 
the fact that they reconcile List/Deque and LinkedHashSet/SortedSet and are 
very useful as parameter/return types in APIs.

> >
> > s'marks
>
> Rémi

Kind regards, Anthony

[1] https://gist.github.com/anthonyvdotbe/e2e313693f032e4336e5385334a476db

Reply via email to