RFR: jsr166 jdk integration 2018-05

John Rose john.r.rose at oracle.com
Sat May 19 22:54:35 UTC 2018


On May 19, 2018, at 9:42 AM, Martin Buchholz <martinrb at google.com> wrote:
> 
> I like thinking of ArrayList as just an optimized HashMap, Lua-style, and
> HashMap.replaceAll also does not increment modCount, supporting our
> "structural modification" position.
> 
> The thing that bothers me most about the status quo is the *inconsistency*
> - between root list and subList, between default implementation and
> concrete implementation, and between ArrayList and HashMap.  And there
> seems to be no reason for users to expect any such inconsistency.

FWIW my $0.02.

Sadly I don’t have time to read this whole CME thread, but it seems to
me that the written spec. has to lead here, not the de facto spec. of
how stuff throws CME today.

And we have to start with the javadoc in CME.java.  Sadly, it is more
allusive than definitive but we have to work with what we have.  When
read closely, as if it were a true spec instead of a mere handful of
examples, supports a pretty narrow interpretation of when CME can be
thrown:

A. When race conditions are detected (not done today at all, but would
be with thread-confined data!).

B. When a backing collection is modified between calls to an iterator
over it.

C. Overlapping cases A and B, when an iterator may experience
“arbitrary, non-deterministic behavior” at some later point.  (This
points, at least, to dangling pointers to inactive backing storage
after a resize, and also to buffering of values in the iterator which
duplicates the backing state.)

D. Finally, a catch-all “sequence of method invocations that violates
the contract of an object”.

The catch-all case D has (maybe) been treated as grounds for adding
lots of additional ad hoc checks in various implementations, but (to
follow the written spec) those ad hoc checks must be clearly
documented as “violating the contract of the object”.  And that means
that the object itself, in its subclass, must have documented a
contract that could be violated by an invalid sequence of calls to
various methods on that object.

At the same time, List (for example) is a very general-purpose object
and as such has a very simple (I’d say “categorical”) contract.  A
subtype of List might have a more rigorous contact and throw more CMEs
but the default for List as a whole the criteria should be as narrow
as possible, subject to the goals A, B, C, above.

This CME thread (the parts on the side of more CMEs) appeals to the
List specification where it says “otherwise perturb it in such a
fashion that iterations in progress may yield incorrect results”,
saying that when we spot a result that seems obviously incorrect, we
are permitted to throw a CME.

But I think in order to follow the spec. we need to insist that the
phrase “incorrect results” has a definite and documented meaning, or
else that it refers (as CME.java does) to some hypothetical subtype of
List that has additional contracts.  The phrase “incorrect results” in
List cannot be carte blanche to add checks where we are afraid the
programmer might have made an error even if we cannot prove one; that
would be just officious mind-reading.

I don’t know whose side this favors more, but I think we all can agree
that a careful and disciplined reading of the spec. will sort us out,
and that a narrow construction of the spec. evidence is probably safer
than a broad one.

Final point: Since the CME spec. says it is a best-effort bug
detection, we have nothing to lose from removing CME throws, if
consistency is the most important goal.  Adding new CME throws surely
must be justified by a careful, conservative reading of the existing
spec., which is what I have tried to provide in this note.

HTH
— John


More information about the core-libs-dev mailing list