Hi Martin,

On 12/03/2015 01:51 AM, Martin Buchholz wrote:
We're stuck.  Peter wants to make Throwables cloneable, I want to
reverse the order of throwables and add the past Throwable as a
suppressed exception to the exception of a dependent action, and Doug
wants the current webrev behavior of adding the dependent action as a
suppressed exception of the source.

I'm willing to accept the small incompatibility of throwing a
different exception when everything fails; the existing spec doesn't
promise what happens in this case.

As said in the other thread, I don't want to delay the changes to CompletableFuture with the support for cloning of exception. If this ever gets accepted (and probably won't) the CompletableFuture and ForkJoinTask could be revisited.

I see we have 3 options now for CompletableFuture:

- do nothing (ignore whenComplete exception when previous stage completes exceptionally too) - add whenComplete exception to the exception from previous stage (as proposed currently in wave 2) which is thread-safe, but modifies the exceptional outcome of previous stage after it has already completed and thus could non-deterministically change the behavior of existing code (very unlikely, but possible). - add the exception from previous stage to whenComplete exception (as endorsed by Martin) which changes the behavior and bends the spec. a little

What about the 4th option (keep current behavior, but try the best-effort with reflection to make new exception of the same type):

...
            } catch (Throwable ex) {
                if (x == null) {
                    x = ex;
                } else {
                    // try to create new exception with same:
// type, cause, suppressed exceptions and stack-trace...
                    Throwable nx;
                    Class<?> xClass = x.getClass();
                    try {
Constructor<?> xConstr = xClass.getConstructor(Throwable.class);
                        nx = (Throwable) xConstr.newInstance(x.getCause());
                    } catch (Exception e1) {
                        try {
                            nx = (Throwable) xClass.newInstance();
                            nx.initCause(x.getCause());
                        } catch (Exception e2) {
                            // no luck
                            nx = null;
                        }
                    }
                    if (nx != null) {
                        // inherit stack-trace of original exception
                        nx.setStackTrace(x.getStackTrace());
                        // inherit suppressed exceptions
                        for (Throwable sx : x.getSuppressed()) {
                            nx.addSuppressed(sx);
                        }
                        // add 'ex' as a final suppressed exception
                        nx.addSuppressed(ex);
                        x = nx;
                    }
                }
            }
            completeThrowable(x, r);

...



Note that such code and similar code in ForkJoinTask.getThrowableException will probably have to be modified for jigsaw to include dynamic addition of read-edge to the module of exception class...

Regards, Peter

Reply via email to