On 4/28/21 7:19 AM, Stuart Marks wrote:
On 4/27/21 9:17 AM, Anthony Vanelverdinghe wrote:
On Tuesday, April 27, 2021 11:25 CEST, Peter Levart
<peter.lev...@gmail.com> wrote:
Now just some of my thoughts about the proposal:
- SortedSet.addFirst/.addLast - I think an operation that would be used
in situations like: "I know this element should always be greater than
any existing element in the set and I will push it to the end which
should also verify my assumption" is a perfectly valid operation. So
those methods throwing IllegalStateException in case the invariant
can't
be kept seem perfectly fine to me.
This was raised before and addressed by Stuart in [0]:
"An alternative as you suggest might be that
SortedSet::addFirst/addLast could throw
something like IllegalStateException if the element is wrongly
positioned.
(Deque::addFirst/addLast will throw ISE if the addition would exceed
a capacity
restriction.) This seems error-prone, though, and it's easier to
understand and
specify that these methods simply throw UOE unconditionally. If
there's a good use
case for the alternative I'd be interested in hearing it though."
Yes, to be clear, it was Stephen Coleborne who raised this previously
[1] and it's my response that's quoted above.
Some further thoughts on this.
This is an example where, depending on the current state of the
collection, the method might throw or it might succeed. This is useful
in concurrent collections (such as the capacity-restricted Deque
above), where the caller cannot check preconditions beforehand,
because they might be out of date by the time the operation is
attempted. In such cases the caller might not want to block, but
instead it might catch the exception and report an error to its caller
(or drop the request). Thus, calling the exception-throwing method is
appropriate.
Something like SortedSet::addLast seems different, though. The state
is the *values* of the elements already in the collection. This is
something that can easily be checked, and probably should be checked
beforehand:
if (sortedSet.isEmpty() || sortedSet.last().compareTo(e) <= 0)
sortedSet.add(e);
else
// e wouldn't be the last element, do something different
I was thinking more of a case where the else branch would actually throw
IllegalStateException and do nothing else - a kind of add with
precondition check. A precondition in the sense of
Objects.requireNonNull(). I can't currently think of a real usecase now,
so this kind of operation is probably very rare. Probably not useful
since if you're adding to SortedSet, the order of elements added should
not matter because SortedSet will sort them. If you just want to check
the order of elements added and you are not willing to pay the price of
SortedSet, you will be adding them to a List or LinkedHashSet, but then
the method would not do the check...
Now this is a fair bit of code, and it would be shorter just to call
sortedSet.addLast(e). But does that actually help? What if e is
already in the set and is the last element?
In that case the operation would be a no-op (or it would replace the
element with the parameter - a slight difference as the element can be
.equals() but not the same instance).
Is catching an exception really what we want to do if e wouldn't be
the last element? Maybe we'd want to do nothing instead. If so,
catching an exception in order to do nothing is extra work.
I was only thinking of situations where propagating the exception would
be the desired thing.
Again, I'd like to hear about use cases for a conditionally-throwing
version of addLast et. al. I don't want to be limited by failure of
imagination, but it does seem like this kind of behavior would be
useful only in a narrow set of cases where it happens to do exactly
the right thing. Otherwise, it just gets in the way, and its behavior
is pretty obscure. So, color me skeptical.
Right, I don't know how common such operation would be. Probably not very.
Peter
which are a continual source of errors.)
I'll think about this more, but it doesn't seem promising.
s'marks