[External] : Re: Sequenced Collections
Stuart Marks
stuart.marks at oracle.com
Tue Oct 11 00:54:21 UTC 2022
It sounds like you're after some generalized notion of "consistency", and the fact
that offer*() return a boolean whereas add*() do not seems inconsistent.
Unfortunately, the methods have different semantics. After add(obj), obj is *always*
a member of the collection, whereas after offer*(obj), obj *might or might not* be a
member of the collection. The semantics of addFirst/addLast are more closely aligned
with those of the add*() methods on Collection, so I decided to promote
addFirst/addLast to SequencedCollection instead of offerFirst/offerLast.
On your other point, if you want to compare elements of a SequencedCollection to
those of another, in encounter order, you can just use regular Iterators for that.
ListIterator isn't necessary.
s'marks
On 10/5/22 3:36 PM, Ernie Rael wrote:
> 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