scala/scala — pull request #2563 by soc (2013-05-18 23:30:14+00:00)
Title: SI-7474 Parallel collections: End the exception handling madness

"What's wrong with an API which non-deterministically returns either
type A or type B(Set(A, ...))?"

This is pretty much what the exception handling behavior of the
parallel collections does: If exceptions of type A occur, either an
exception of type A or an exception of type B, wrapping multiple
exceptions of A's, are returned.

This behavior is incredibly broken and so unintuitive, that even
people writing tests don't handle it correctly.
See files/run/t5375.scala.

Concerning “non-deterministic”:
How many exceptions are observed before the operation is aborted
depends on the machine, the available cores and hyper-threading,
the operating system, the threadpool implementation and
configuration, the size of the collection and the runtime itself.

In fact, files/run/t5375.scala is failing on both jdk7u and Avian
because of this issue.

With this change, we just pass the "first" exception which occurs.
This seems to be what C# and Java both do, too.

“Why don't we wrap everything in CompositeThrowables?”
Even consistently returning CompositeThrowable doesn't make much
sense (because we have fail-fast behaviour and don't wait until
all tasks have finished or have thrown an exception).
Therefore, there is no useful semantic in having a
CompositeThrowable which returns "some" exceptions.

Either
a) gather and return all the exceptions or
b) just return one, instead of wrapping a non-deterministic
number of exceptions into a completely unrelated wrapper type.

Considering that changing the parallel collection semantics in
such a profound way as described in a) is out of question, the
second option is chosen.

As soon as Scala targets Java > 7 Throwable#addSurpressed can be
used to add further exceptions to the one which gets returned.