3

In a Cyclops React "Try with Resources" block, I would like to map an IOException to a custom exception type. I have tried this also with Javaslang and seems less fexible since it treats all exceptions the same.

Code example:

private static Try<String, ConnectionError> readString() {
    // Socket is a thread-local static field
    final Try<String, IOException> string = Try.catchExceptions(IOException.class)
            .init(() -> new BufferedReader(new InputStreamReader(socket.get().getInputStream())))
            .tryWithResources(BufferedReader::readLine);

    return string.isSuccess() ? Try.success(string.get()) :
            Try.failure(new ConnectionError("Could not read from server", string.failureGet()));
}

Could this be done in more elegant way? Or does not make any sense and it would be better to return Try<String, IOException>?

Disclaimer: I am a newbie using the Cyclops React library and functional programming in general, so I may have severe conceptual miscomprehensions.

Xavier Arias
  • 162
  • 2
  • 10

2 Answers2

5

Starting with Javaslang 2.1.0 it will be possible to do the following:

Try<String> of = Try.withResources(() -> new BufferedReader(new InputStreamReader(socket.get().getInputStream())))
                    .of(BufferedReader::readLine)
                    .mapFailure(
                        Case(instanceOf(IOException.class), ConnectionError::new)
                    );

I.e. we added the Try.withResources functionality and are now able to map a failure.

The mapFailure method takes a variable amount of match cases. When the exception is not matched (and therefore not mapped), the original exception remains.

I think it makes no sense to include an exception type as part of the Try signature, e.g. Try<String, IOException>, because a computation may throw one of several exceptions.

Specifying a set of possible exception types also does not help because the type information gets lost when the compiler computes the upper bound of the generic.

Disclaimer: I'm the creator of Javaslang

Daniel Dietrich
  • 2,262
  • 20
  • 25
  • Thanks Daniel. At this time do you have an idea on when this version will be available? – Xavier Arias Mar 28 '17 at 12:43
  • 1
    It will be release with the upcoming 2.1.0-beta (start of April). Currently there are 21 open issues targeted for 2.1.0. I see 5 issues that will take a bit time and some backward-compatibility fixes that have to be done until we can ship it. In short, I target May (for the final version). – Daniel Dietrich Mar 28 '17 at 21:40
  • It would be very helpful if this answer included the relevant imports, because the identifiers are generic enough it's hard to know where to get started. – chrylis -cautiouslyoptimistic- Apr 29 '19 at 08:11
1

You can use the 'visit' method to convert the failure type. All cyclops-react types have a visit method or 'catamorphism'. This allows you to match against the internal state of that data type. In the case of Try it takes two functions, one that is executed if the Try is a Success, the other if it is a Failure.

private static Try<String, ConnectionError> readString() {
    // Socket is a thread-local static field
    return Try.catchExceptions(IOException.class)
              .init(() -> new BufferedReader(new InputStreamReader(socket.get().getInputStream())))
              .tryWithResources(BufferedReader::readLine)
              .visit(Try::success,
                     e->Try.failure(new ConnectionError("Could not read from server", e));
}

There are large conceptual / design differences between Vavr / Javaslang Try and the cyclops-react Try. One or the other may be better suited for different use cases. (Daniel can give an overview of the rationale behind Vavr Try).

The cyclops-react version handles only explicitly named Exceptions, and retains that type information. Hence cyclops-react Try takes two generic parameters, one for the success type and one for the most general inferred exception type.

The cyclops-react Try typically does not catch exceptions in ongoing fluent operations (such as map / flatMap etc), although it can be configured to do so.

A core design goal of the cyclops-react Try is avoid hiding bugs. There is a more detailed overview on this StackExchange answer.

John McClean
  • 5,225
  • 1
  • 22
  • 30