Combining Futures And Options in Scala

Alexander Weinmann
3 min readJun 20, 2019

--

If you program a lot in Scala, some patterns occur over and over again. For me it was a combination of a Future and an Option, plugged together as Future[Option[T]]. That type corresponds to something that might be happening in the future, but it might also not happen under certain circumstances that I as a programmer can potentially control. Only in the case of an unexpected exception, the Future will fail. Under certain well defined circumstances nothing will happen and the Future will complete with None.

Both Future and Option are Monads, so it is straightforward to use map(..) and flatMap(..) with them.

I like Monads very much ever since I discovered them. The concept is abstract, but it can be handled in an intuitive manner very easily as soon as you caught the basics. I am a pragmatic programmer, and I am self trained to a very large degree. So I know enough about functional programming to use it, but I will never reach academic heights with it. – But should I? No! Scala is a programming language, so the language itself should help me to advance and find more advanced abstractions based on the basics. So in this case I deliberately take the risk to solve a problem that others might know more about than I do.

In the case of combining Futures and Options it is very much obvious how to go on, so I will briefly describe my ideas about it. But I am sure that I will not be the first who has a solution for the problem. Most likely there are more generic solutions that can be applied to any situations involving two or even more Monads. Such solutions would be even more usable than mine. But let us not go too deep into theoretical constructs! Let us stick to the basics and do what seems to be almost obvious. You can never know everything. There need to be ways for the average programmer to do elegant work without an exhaustive theoretical background.

The goal is to have an equivalent to map(..) and flatMap(..) for that type that will call an optional future from now on. When I miss a function, I often use implicit classes, because they can help me to improve an existing interface. So I will also proceed like that in this situation:

implicit class FutureOption[T](val m: Future[Option[T]]) {
}

To avoid awkward naming conflicts I use slightly different names for my methods. I will call them fmap(..) and fflatMap(..).

Now there just remains some happy coding:

def fmap[U](tf: T => U)(
implicit executionContext: ExecutionContext): Future[Option[U]] = m.map(_.map(tf(_)))

This just corresponds to the usual map(..)-function and yields the same flexibility to optional futures.

A little bit more interesting might be the implementation of fflatMap(..)

def fflatMap[U](tf: T => Future[Option[U]])(
implicit executionContext: ExecutionContext): Future[Option[U]]= this.m
.flatMap(_.map(tf(_)).getOrElse(Future { None }))

If you ever try to write such stuff yourself, you might end up not really understanding your own coding. Don’t worry! The Scala-Compiler does understand you better than you can understand yourself. Type safety will come to your rescue! As long as you know which return type you want to reach in the end, it can sometimes be enough to do some trial and error. I use Intellij, and the Scala-Plugin in this IDE helps by dynamically showing me the return type of my function. If it is not the return type I need, I just keep trying, and I will sooner or later get what I want. With such external help it is becoming possible to tame really frightening code snippets. You will be fluent!

Now you know everything you need to know to manage optional futures! Even if you are new to Futures, it might help you to get more fluent with them. Try not to think too much about mere technicalities like Futures and Options. They are here to help you and have no other justification for their existence than just being helpful. What you are really interested in, is always the type T, and this depends on your use case, so I cannot tell you about it. That is why it is parametrized here.

Scala is a wonderful programming language! This article is good, if it could help you love it as much as I do.

--

--