Should functions that return Future[A] throw exceptions?

Should functions that return Future[A] throw exceptions?

I have come across functions that return Future but also throw exceptions immediately. For example like this: 
def func(): Future[String] {
  if (something) {
     // this
     Future.failed(new RuntimeException("test"))
  } else {
     // and this
     throw new RuntimeException("test")

This behaviour seems annoying for the caller, because you have to do something like this to catch both errors:
try {
  func() recover {
    case e: Exception => handleError(e)
} catch {
  case e: Exception => Future.successful(handleError(e)) //or Future.failed etc

I have noticed that the WSClient in play framework does this (both throwing exceptions if the URL is malformed, and returning a Future which fails if the HTTP request fails).
Is this good practice? Is there a better way to handle errors from functions that behave like this?


Answer 1:

Future is used to return something eventually, but its not clear when this actually happens.

Coming from a .NET perspective (we have Task): an exception should be thrown if the request is clearly invalid (such as an malformed url). You already know this before actually making the web request, so there is no need in delaying the exceptions.

Related:  Calling a method on the superclass in a self-typed trait in scala

On the other hand, if the server is down (timeout?) or the server returns something your client doesn’t understand: this can and must be handled at a later time, since the response is not directly available when making the call. We would be able to block until the response is available, but that would render the Future useless.

I think this is best compared with the ‘Exit early’ programming style.