Should functions that return Future[A] throw exceptions? - scala

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?

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.
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.

Related

Autofac - (Global) Handler/Middleware to unwrap exceptions

We would like to add a handler/middleware to Autofac to essentially unwrap any Autofac.Core.DependencyResolutionException; to throw the inner exception.
Hooking the Activation (or RegistrationPipelineStart) Pipeline phases (using the following code) unwraps one of the exceptions, but the exception ultimately get wrapped by another DependencyResolutionException.
container.RegisterServiceMiddleware<IOController>(PipelinePhase.ResolveRequestStart, (context, next) =>
{
try
{
next(context);
}
catch (Exception ex)
{
// This unwraps one exception, but even if this is done another exception is wrapped.
// If the inner exception is not thrown, there is a DependencyResolutionException wrapped in another DependencyResolutionException
throw ex.InnerException;
}
});
Irrespective of the phase, I always end up with the exception being wrapped.
I think I need to override the behaviour of ActivatorErrorHandlingMiddleware, but I cannot see a way to do this.
(I understand that Constructors should be lightweight an not throw exceptions, but we have a very large application, and are in the process of refactoring the internals...this will take several versions/iterations, so not really a possibility).
Many Thanks in advance.

Throwing Exceptions in Dart for Invalid Parameters (e.g. Sign In)?

I have an async function signIn in a Dart program that takes username and password string arguments. The function calls a remote server and the server responds with a session token or validation messages in the case of missing or incorrect username and/or password.
Currently I have this implemented with callbacks. The appropriate callback is called after the server responds. No need for await.
signIn(username, password, onSuccess, onFailure);
The more I read about Dart, I feel like the above isn't really the Dart way of doing things. Should I be using await combined with try and catch? Something like the following?
try {
sessionToken = await signIn(username, password);
// navigate from the sign in screen to the home screen.
} on InvalidParams catch (e) {
// e contains the server's validation messages
// show them to the user.
}
Invalid sign in credentials are likely. Handling them is normal program flow. I was taught never to use try/catch for regular, expected program flow. It seems that the Dart language is encouraging using exception handling for this especially in combination with await.
From Error class documentation [Emphasis mine.]
If the conditions are not detectable before calling a function, the
called function should not throw an Error. It may still throw a value,
but the caller will have to catch the thrown value, effectively making
it an alternative result rather than an error. The thrown object can
choose to implement Exception to document that it represents an
exceptional, but not erroneous, occurrence, but it has no other effect
than documentation.
What's the best most Dart way to implement this?
Error vs. Exception
The documentation you linked essentially says that the Error class should not be used for what you define as "regular, expected program flow" but Exception should. This also means that using try-catch for addressing these kinds of cases is encouraged in Dart.
From the documentation, Error's should be used for "a program failure that the programmer should have avoided", i.e. unexpected program flow. However, Exception's are "intended to convey information to the user about a failure, so that the error can be addressed programmatically", i.e. expected program flow.
In order to implement exceptions, you will have to extend Exception and create your own exception class. Dart enforces this by not providing access to the message passed to a regular Exception.
Creating instances of Exception directly with new Exception("message") is discouraged, and only included as a temporary measure during development, until the actual exceptions used by a library are done.
Example
enum InvalidCredentials { username, password }
class InvalidCredentialsException implements Exception {
final InvalidCredentials message;
const InvalidCredentialsException({this.message});
}
function() {
try {
await signIn(username, password);
} on InvalidCredentialsException catch (e) {
switch (e.message) {
case InvalidCredential.username:
// Handle invalid username.
break;
case InvalidCredential.password:
// Handle invalid password.
break;
}
} on Error catch (e) {
print(e);
} catch (e) {
// Handle all other exceptions.
}
}
I created InvalidCredentialsException to handle invalid credentials passed to signIn. For the message (you can call it whatever you want), I simply used an enum to distinguish between an invalid username and an invalid password (probably not what you would want to do, it should just explain the concept).
When handling it using try-catch, you can create different catch-blocks for different types. In my example, I use on InvalidCredentialsException for responding to the expected exception in your program flow and another one on Error for unexpected failures.
When using on for catch-statements, you run the risk of not catching other types of exceptions, which will then be thrown. If you want to prevent that, you can either have another block for generic exceptions, i.e. on Exception or just have a generic catch-block at the end (catch (e)).
You might want to override toString in your exception class if you want to be able to print out your exception.
Additionally, you can obviously transport as much information with your exception as you like, e.g. (modified from the above code):
// ...
throw InvalidCredentialsException(cause: InvalidCredentials.password, message: password);
// ...
class InvalidCredentialsException implements Exception {
final InvalidCredentials cause;
final String message;
const InvalidCredentialsException({this.cause, this.message});
}

Confused about exception throwing in failed Scala futures

I have the following code:
private def getAPIResult(token: String, apiCall: String):Future[JsValue] = {
WS.url(apiCall)
.withHeaders("Authorization" -> ("Bearer " + token))
.get().map(response =>
response.status match {
case 200 => Json.parse(response.body)
case 401 => throw new RuntimeException("Authorization failed, we really need to handle this: " + response.body)
case _ => throw new RuntimeException("Web service call failed: " + response.body)
}
)
}
I need to handle the two failure cases - one where I get a HTTP 401 response and the other where something else more generic went wrong.
I'm sure I've read that it's 'bad practice' to throw exceptions in functional programming, but is that what I'm doing here? Aren't I just failing the future?
I need to be able to handle that 401 response, so I am thinking of creating a new Exception class (called something like UnauthorizedException) so that methods that call getApiResult can distinguish between a 401 and any other error. Before I do this though, I want to make sure that using exceptions like this is considered good practice, or if there is a better way to do this.
I'm sure I've read that it's 'bad practice' to throw exceptions in functional programming, but is that what I'm doing here? Aren't I just failing the future?
A failed future is just a value. Throwing exceptions is generally considered a bad practice because it doesn't behave like returning a value.
I need to be able to handle that 401 response, so I am thinking of creating a new Exception class (called something like UnauthorizedException) so that methods that call getApiResult can distinguish between a 401 and any other error. Before I do this though, I want to make sure that using exceptions like this is considered good practice, or if there is a better way to do this.
Yes, it's perfectly fine. One problem is that it isn't obvious from the signature that UnauthorizedException needs to be dealt with separately.
For a private API this matters very little. If you still want to avoid it, you can do something like
sealed trait Response
case class Ok(value: JsValue) extends Response
case class Unauthorized extends Response
// possible
case class OtherError(e: Exception) extends Response
private def getAPIResult(token: String, apiCall: String):Future[Response] = ...
but of course, now all clients have to deal with it.

My http request becomes null inside an Akka future

My server application uses Scalatra, with json4s, and Akka.
Most of the requests it receives are POSTs, and they return immediately to the client with a fixed response. The actual responses are sent asynchronously to a server socket at the client. To do this, I need to getRemoteAddr from the http request. I am trying with the following code:
case class MyJsonParams(foo:String, bar:Int)
class MyServices extends ScalatraServlet {
implicit val formats = DefaultFormats
post("/test") {
withJsonFuture[MyJsonParams]{ params =>
// code that calls request.getRemoteAddr goes here
// sometimes request is null and I get an exception
println(request)
}
}
def withJsonFuture[A](closure: A => Unit)(implicit mf: Manifest[A]) = {
contentType = "text/json"
val params:A = parse(request.body).extract[A]
future{
closure(params)
}
Ok("""{"result":"OK"}""")
}
}
The intention of the withJsonFuture function is to move some boilerplate out of my route processing.
This sometimes works (prints a non-null value for request) and sometimes request is null, which I find quite puzzling. I suspect that I must be "closing over" the request in my future. However, the error also happens with controlled test scenarios when there are no other requests going on. I would imagine request to be immutable (maybe I'm wrong?)
In an attempt to solve the issue, I have changed my code to the following:
case class MyJsonParams(foo:String, bar:Int)
class MyServices extends ScalatraServlet {
implicit val formats = DefaultFormats
post("/test") {
withJsonFuture[MyJsonParams]{ (addr, params) =>
println(addr)
}
}
def withJsonFuture[A](closure: (String, A) => Unit)(implicit mf: Manifest[A]) = {
contentType = "text/json"
val addr = request.getRemoteAddr()
val params:A = parse(request.body).extract[A]
future{
closure(addr, params)
}
Ok("""{"result":"OK"}""")
}
}
This seems to work. However, I really don't know if it is still includes any bad concurrency-related programming practice that could cause an error in the future ("future" meant in its most common sense = what lies ahead :).
Scalatra is not so well suited for asynchronous code. I recently stumbled on the very same problem as you.
The problem is that scalatra tries to make the code as declarative as possible by exposing a dsl that removes as much fuss as possible, and in particular does not require you to explicitly pass data around.
I'll try to explain.
In your example, the code inside post("/test") is an anonymous function. Notice that it does not take any parameter, not even the current request object.
Instead, scalatra will store the current request object inside a thread local value just before it calls your own handler, and you can then get it back through ScalatraServlet.request.
This is the classical Dynamic Scope pattern. It has the advantage that you can write many utility methods that access the current request and call them from your handlers, without explicitly passing the request.
Now, the problem comes when you use asynchronous code, as you do.
In your case, the code inside withJsonFuture executes on another thread than the original thread that the handler was initially called (it will execute on a thread from the ExecutionContext's thread pool).
Thus when accessing the thread local, you are accessing a totally distinct instance of the thread local variable.
Simply put, the classical Dynamic Scope pattern is no fit in an asynchronous context.
The solution here is to capture the request at the very start of your handler, and then exclusively reference that:
post("/test") {
val currentRequest = request
withJsonFuture[MyJsonParams]{ params =>
// code that calls request.getRemoteAddr goes here
// sometimes request is null and I get an exception
println(currentRequest)
}
}
Quite frankly, this is too easy to get wrong IMHO, so I would personally avoid using Scalatra altogether if you are in an synchronous context.
I don't know Scalatra, but it's fishy that you are accessing a value called request that you do not define yourself. My guess is that it is coming as part of extending ScalatraServlet. If that's the case, then it's probably mutable state that it being set (by Scalatra) at the start of the request and then nullified at the end. If that's happening, then your workaround is okay as would be assigning request to another val like val myRequest = request before the future block and then accessing it as myRequest inside of the future and closure.
I do not know scalatra but at first glance, the withJsonFuture function returns an OK but also creates a thread via the future { closure(addr, params) } call.
If that latter thread is run after the OK is processed, the response has been sent and the request is closed/GCed.
Why create a Future to run you closure ?
if withJsonFuture needs to return a Future (again, sorry, I do not know scalatra), you should wrap the whole body of that function in a Future.
Try to put with FutureSupport on your class declaration like this
class MyServices extends ScalatraServlet with FutureSupport {}

How to correctly handle errors on iPhone

I have a question about error/exception handling on the iPhone.
I've read the documentation about Exception, and it seems exceptions can be used only for exceptional situations.
Does it mean you can't use them like in java ?
for example, I'm trying to write a use case controller for my application. I've got a few examples in Java from previous projects in that language, that use exceptions in case of errors.
the question put simply is: can I follow the example I've got in Java, and "translate" it in Objective-C (and use Objective-C exceptions) or is there a better way to do that ?
here is the code I would like to make objective-c friendly:
public void addPerformance(Perfomance perf) {
//do some preparation
...
//execute the usecase
executor(new AddPerformance(perf));
}
private void executor(Usecase usecase) {
try {
UnitOfWorkServices.INSTANCE.bizTransactionStart();
usecase.execute();
UnitOfWorkServices.INSTANCE.bizTransactionCommit();
} catch (RealException re) {
UnitOfWorkServices.INSTANCE.bizTransactionEscape();
throw re;
} catch (Exception e) {
UnitOfWorkServices.INSTANCE.bizTransactionEscape();
throw new FatalException(this.getClass().getName() + " / executor("
+ usecase.getClass().getSimpleName() + ")", e,
"APPXCP_006_UNEXPECTED_EXCEPTION",
"\n\t |*| : Unexpected exception translated into FatalException");
} finally {
UnitOfWorkServices.INSTANCE.bizTransactionEnd();
}
}
All the exceptions are meant to be caught by the UI to display an error message.
thanks for your help,
Michael
In general, yes, you can translate your try/catch logic into a comparable construct in Objective-C and get comparable results. Though do be careful with that throw re; line, as an uncaught exception on the iPhone will crash your app.
More to the point however, the standard pattern used by the iPhone SDK and other commonly used libraries is that instead of throwing exceptions, API methods that may fail for a variety of reasons return a boolean value indicating whether or not the operation was successful, and accept as a parameter a reference to an NSError pointer that is used in the event of an error to provide the caller with specific details about what went wrong. So in this case, your code might translate to something more like:
NSError* error = nil;
[[UnitOfWorkServices sharedInstance] bizTransactionStart];
bool success = [usecase execute:&error];
if (success) {
[[UnitOfWorkServices sharedInstance] bizTransactionCommit];
}
else if (error) {
int code = [error code];
[[UnitOfWorkServices sharedInstance] bizTransactionEscape];
if (code == MY_MINOR_ERROR_CODE) {
//do something
}
else if (code == MY_FATAL_ERROR_CODE) {
//do something else
}
else {
//handle unexpected error type(s)
}
}
else {
//operation failed with no specific error details
[[UnitOfWorkServices sharedInstance] bizTransactionEscape];
//handle generic error
}
[[UnitOfWorkServices sharedInstance] bizTransactionEnd];
You can use exceptions just as you would use exceptions in Java, but it is not the recomended way to do it. Translating Java to Objective-C that way works, and most people will understand your intentions. But the result will be just as bad as if you tried to translate English to German using a dictionary; the spelling is perfect, but the grammar and context is completely wrong.
Understanding the "Cocoa way" to handle errors and exceptions will help you create more robust iOS applications, and give you a better understanding of how to use the official and third party API:s.
I have written a longer blog post on the topic here: http://blog.jayway.com/2010/10/13/exceptions-and-errors-on-ios/
Lets recap the important parts:
Exceptions should only be used for programming errors, and fatal stuff that you can not recover from. For example out of bounds exception, if you called with the wrong argument the first time your app is in error, retrying 100 times will not fix your app, only keep failing. The exceptions are exceptions to normal workflow and there to help you fix all bugs before you ship the app to end users.
NSError instances is what you use for errors caused by the users, and stuff that your application can recover from. For example IO-errors, the user might want to re-connect to the network, try a new password, and try again. This is for errors that you can predict, and that the app or the user can do something about.