Sequenced Collections

Ernie Rael errael at raelity.com
Wed Oct 5 22:36:05 UTC 2022


On 10/5/22 9:34 AM, Stuart Marks wrote:
>
>
> On 10/4/22 9:38 PM, Ernie Rael wrote:
>> Summary of key points (maybe the mail was TL;DR)
>
> OK thanks, I was still mulling over the previous email wondering which 
> parts were significant enough to reply to.
>
>>   * SequencedCollection methods addFirst,addLast are the only methods in
>>     Collection hierarchy (AFAIK) that might modify the collection and do
>>     not return/signal if the collection was modified. Seems like
>>     offerFirst,offerLast are more consistent with Collections and still
>>     avoid method proliferation.
>
> The problem is that the boolean return values from add() and from 
> offerX() mean different things, and having them be adjacent on List 
> would be confusing. (Yes, they're both present on Deque, which is one 
> of the reasons Deque is too complicated.) And we couldn't adjust the 
> semantics of SequencedCollection.offerX() to match add(), as that 
> would clash with the existing semantics on Deque.


It is not uncommon for a sub-interface/sub-class to clarify the precise 
meaning of a method. If there's a general definition of 
SequencedCollection.offerFirst(e), then the Deque definition clarifies 
the meaning in that context. Consider:

Collections.add(e) - Returns true if this collection changed as a result 
of the call
List.add(e) - Return true
Set.add(e) - Returns true if this set did not already contain the 
specified element


>
> From your other messages it seems like you want the boolean return 
> value in order to keep track of whether the collection changed such 
> that it affects equals() and hashCode(). 


No, I was just discussing the relationship of change and equals() when 
working with a SequencedCollection; it's more observations around using 
SeqCol. It's interesting that an addAll() can permute the structure, and 
end up at the same place.


> There are other methods that might modify collections where you can't 
> tell whether they actually modified the collection; consider 
> Collection::clear or List::replaceAll. 


I'll be more precise: methods that work with a single item return/signal 
change; most bulk operators such as removeif(), retainAll(), 
removeAll(), addAll() also return/signal change.

My main point is that "void SequencedCollection.addFirst(e)" is 
inconsistent with Collections' design. clear() is, well, clear(). 
replaceAll() seems to be an exception (a lone exception?).


> So I don't think the boolean return value from add/offer is really 
> buying you all that much.


When I put together a class based on a Collection, I like to follow the 
general design pattern. Not sure if/when I may have used the "return 
change" when using a collection. But when sub-classing a collection, 
since everything does it, so do I; I'll return change in any additional 
methods I might add. Consistent, least surprise...


>
>>   * With LinkedHashSet, seems like listIterator is missing. Rather than
>>     making that part of SequencedCollection, maybe an "interface
>>     ListIterable { ListIterator listIterator(int index); }". In addition
>>     to modification, bi-directional might also be optional, to support
>>     it's use with list equals.
>
> ListIterator has indexes and so it's pretty much tied to List. Maybe 
> what you're missing from LinkedHashSet 


I want to be able to do List.equals(SequencedCollection) and vice versa 
(in particular with LinkedHashSet). In the list equals() implementations 
I've looked at, they all use two ListIterator to do the compare; only 
forward iteration.  For equals(), I think can wrap the 
SequencedCollection iterator in a forward, uni-directional listIterator, 
a little messy, and use that for equals(); support from the 
infrastructure would be nice. Which is where the idea of "ListIterator 
Collections.listIterator(iterator, index)" in the other email comes from.

Some daydreaming: For equals(), indexes don't matter except for 
initialization. And as far as "index ... tied to list", if 
SequencedCollection had a listIterator, I think I could form 
sub-sequence from that, with only forward iteration. But 
sub-SequencedCollection is a different topic. My usage requirement now 
is for equals().

Lists may include index, but they don't really depend on it unless 
they're RandomAccess; consider LinkedList. I don't see how indexes have 
a bearing on this discussion; in a listIterator the index is 
contained/maintained in the iterator.


> is the ability to insert or reposition an element somewhere in the 
> middle? This is certainly a valid use case, but it's quite rare, and 
> I'm not sure I'd want to support it using an Iterator style mechanism 
> anyway.
>
> Surveying the usages of ListIterator, 


The implicit use by equals() is missing.


> I found that it's mainly used for iteration in reverse, and 
> secondarily for replacing all the elements of a List (somewhat 
> supplanted by replaceAll). We did run into one case where ListIterator 
> was used to edit items within a list but it turned out to be 
> INCREDIBLY clumsy to use. So if we want to support that (fairly rare) 
> use case, I wouldn't start with a ListIterator or some variant with 
> indexes removed. I'd also want to see use cases before considering 
> adding new mechanisms.
>
> s'marks
>



More information about the core-libs-dev mailing list