# immutables

Asynchronous applications are much harder to debug. You do not get the whole stack trace so easily. So it is important to react to all the exceptions that might unexpectedly occur. I found a case when following a simple pattern to run futures in parallel leads to loss of exceptions. In this post I describe a solution for that.

## Future[A]

Future[A] represents an asynchronous computation. It may result in a value of type A or an exception. It is possible to apply a function A => B to the potential value using map[B](f: A => B) or apply a function A => Future[B] using flatMap[B](f: A => Future[B]). Both results in a new future of type Future[B]. The latter can be used to sequence computations that depend on the value of previous ones.

In practice it is more convenient to use for-comprehensions as a syntactic sugar for a sequence of maps and flatMaps.

What if we want to execute multiple futures in parallel? I often see the following pattern as a solution. It works because scala Future starts the asynchronous computation immediately.

What is the problem with this approach? If both futures fail, only the first exception is returned. The second one is lost.

How to collect all the exceptions? For instance, the same way that parallel validation in cats does - using the applicative type class. See validated as a reference.

## Applicative[Future]

Add "org.typelevel" %% "cats" % "0.7.0" as a dependency to run the snippets. First, let’s obtain the default applicative instance for scala futures and see how it works.

It still behaves the same way as before. Apparently, the default implementation of applicative for future just uses flatMap. We need to create our own implementation.

Here I used Semigroup type class to combine exceptions. An example implementation of Semigroup[Throwable] may look like this:

Where Exceptions is a class that represents multiple exceptions merged together. The problem with this solution is that some recover block may fail to catch the previously excepted exception. However, it does it job. It preserves the stack traces and messages.

Let’s see what happens if we use this implementation.

Now it is possible to see that both futures failed.