Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Future.block() #1883

Closed
Diagoras opened this issue Mar 2, 2017 · 2 comments
Closed

Add Future.block() #1883

Diagoras opened this issue Mar 2, 2017 · 2 comments

Comments

@Diagoras
Copy link

Diagoras commented Mar 2, 2017

There currently exists Future.get(), which is close to what I want, but will throw a NoSuchElementException instead of the underlying exception in the event of a failed future. I'd like an easy way to block on a Future, and force it to throw any exception that might have terminated its run.

@danieldietrich
Copy link
Contributor

danieldietrich commented Mar 2, 2017

Hi, thank you for your suggestion. Currently (2.0.5) there is an ugly workaround:

future.await();    // blocks until completed and returns the future instance
future.getValue() // returns Option<Try<T>>
      .get()      // returns a Try<T> because we know that the Option is a Some
      .get();     // returns a Value of type T or throws a NonFatalException that wraps the original exception

With Javaslang 2.1.0 await() will return the Future instance.

Value sits at the top of the Javaslang type hierarchy. Currently it defines an abstract get() that throws NoSuchElementException in the empty case. However, Try extends Value and Try.get() throws a NonFatalException (which can be considered as a bug, it should throw a NoSuchElementException).

However, in 3.0.0 there will be some changes. I think we should allow get() to throw an arbitrary (non-fatal?) exception in the empty case. Additionally we will get rid of the NonFatalException wrapper by sneaky throwing arbitrary exceptions at runtime.

Then your wish could be expressed like this:

// a future Javaslang 3.0.0
future.get();

Until that you could use this helper:

import javaslang.concurrent.Future;
import javaslang.control.Try;

public class Test {

    public static void main(String[] args) {

        Future<String> future1 = Future.successful("ok");
        System.out.println(block(future1));

        Future<String> future2 = Future.failed(new Exception("error"));
        System.out.println(block(future2));
        
    }

    static <T> T block(Future<T> future) {
        future.await();
        final Try<T> result = future.getValue().get();
        if (result.isEmpty()) {
            sneakyThrow(result.getCause());
        }
        return result.get();
    }

    @SuppressWarnings("unchecked")
    static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
        throw (T) t;
    }

}

Adding an additional block() method is currently no option for us because we want to keep the API as thin and simple as possible, await().get() will do the job. But it will take some time until 3.0.0 will be released... Too much to do, too few time.

@danieldietrich
Copy link
Contributor

Fixed with #1976

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants