On 06/13/2013 04:47 PM, Paul Sandoz wrote:
On Jun 13, 2013, at 4:06 PM, Remi Forax <fo...@univ-mlv.fr> wrote:
There is a difference between an Iterator/forEach and a spliterator/stream,
with a stream you know that the called lambdas will not interfere and mutate
the source collection.
You do? I don't think there is any conceptual difference between the following
w.r.t. interference:
ArrayList l = ...
l.stream().filter(...).forEach(e -> l.add(e));
l.spliterator().forEachRemaining(e -> l.add(e));
and:
ArrayList l = ...
l.forEach(e -> l.add(e));
l.iterator().forEachRemaining(e -> l.add(e));
Of course we have (or will have) strong wording saying don't implement
interfering lambdas, but we still have to check for co-modification in the
traversal methods of ArrayList spliterator.
Isn't it because if you remove an element from an ArrayList while iterating you
can see a stale value ?
While with a HashMap, if you have only one thread, you can not see a stale
entry ?
Assuming just one thread do you agree that in all of the above examples the only
way the list can be interfered with is by the Consumer instance e -> l.add(s) ?
yes, as I said to Mike, what is important IMO is that the semantics of
forEach and the semantics of for(:) should be the same.
So a spliterator on HashMap can only check the modCount at the end unlike the
one on ArrayList that need to check at each step.
The ArrayList.spliterator.forEachRemaining implementation also checks at the
end.
Given that a spliterator is something new which is weaker than an
iterator, the semantics can be relaxed.
For ArrayList, because you can see a stale entry if you mutate during a
forEachRemaining,
you have no choice but checking at each step. And because the semantics
is not tight to the iterator one,
I agree that you can also perform a check at the end.
For HashMap.spliterator.forEachRemaining, because you can not see stale
entry (without concurrency),
you can only perform a check at the end. It's IMO also a valid semantics.
Paul.
Rémi