Search code examples
javaexceptionapi-designvavr

Is a method that returns a Try allowed to throw?


We're using Vavr in our project to ease exception handling. I always make sure that a method that returns a Try can never throw anything, like so:

public Try<Result> someSafeMethod() {
  return Try.of(() -> someService.generateId())
           .map(someOtherService::getValueForId)
           .map(mappingService::mapToResult);
}

but some of my colleagues would implement it like this:

public Try<Result> someSafeMethod() {
  String generatedId = someService.generateId(); // <- Might throw an Exception that is not caught by the Try clause
  return Try.of(() -> someOtherService.getValueForId(generatedId))
           .map(mappingService::mapToResult);
}

Arguing that if something is wrong with the generation of the ID that they would rather the exception is thrown instead of the returned Try being a failure.

The documentation does not prohibit that a method returning a Try should not throw, but it does state that:

Try is a monadic container type which represents a computation that may either result in an exception, or return a successfully computed value.

Am I being too too strict? Imagine you would use an API where all methods return a Try, wouldn't it be bad when they still throw?


Solution

  • You are not being too strict.

    The whole point of using Try as a return value is the resulting benefit of programming with total functions and having a composable way of handling errors. Total functions are functions that always return a value of the declared return type for all possible argument values. If they are throwing exceptions, their functions are not total functions anymore, and—without explicit error handling—non-totality will propagate transitively through their code, 'infecting' all other functions that call them with non-totality. As a result, they will end up with code that will be much harder to reason about and it will take more effort to make sure it is correct.

    Throwing exceptions while using Try would also defy the purpose of using Try in the first place and it would unnecessarily complicate the code consuming their API for no obvious benefit, because the API consumers will have to do error handling both using Try and catching exceptions.