Mike Slinn

Connoisseur of Technology

Better Syntactic Sugar for Scala Futures

2017-05-25 / All Blog posts

Ever since Scala's Futures were initially provided as part of Akka 2.0, programmers have been confused by the non-intuitive syntax. That is why ScalaCourses.com dedicates an entire lecture to For-comprehensions With Futures, as part of an 8 lecture series on Scala Futures within the Intermediate Scala course.

As Viktor Klang points out in his blog, the following code does not run 3 Futures in parallel:

  def doSomething(someParameter: SomeType)
                 (implicit ec: ExecutionContext): Future[Something] =
    for {
      v1 <- Future(someCalculation())
      v2 <- Future(someOtherCalculation())
      v3 <- Future(someDifferentCalculation())
    } yield doSomethingWith(v1, v2, v3)

The compiler has no way of ascertaining the programmer's intent – perhaps it is desirable for some reason to run the 3 Futures one after the other.

Viktor suggests this syntax to make futures run in parallel:

  def doSomething(someParameter: SomeType)
                 (implicit ec: ExecutionContext): Future[Something] =
    for {
      f1 = Future(someCalculation())
      f2 = Future(someOtherCalculation())
      f3 = Future(someDifferentCalculation())
      v1 <- f1
      v2 <- f2
      v3 <- f3
    } yield doSomethingWith(v1, v2, v3)

While Viktor's solution works, it is verbose. Worse, it silently fails to run the futures in parallel if the programmer accidently writes even one of the expressions out of order:

  def doSomething(someParameter: SomeType)
                 (implicit ec: ExecutionContext): Future[Something] =
    for {
      f1 = Future(someCalculation())
      v1 <- f1
      f2 = Future(someOtherCalculation())
      v2 <- f2
      f3 = Future(someDifferentCalculation())
      v3 <- f3
    } yield doSomethingWith(v1, v2, v3)

Again, the compiler has no way of ascertaining the programmer's intent, so it should not generate an error or warning message.

We Need A Macro

A new right-associative operator, implemented as a Scala macro, would make the programmer's intent clear. Let's call this operator <=: (parallel generator). The above code could be rewritten using the parallel generation operator like this:

  def doSomething(someParameter: SomeType)
                 (implicit ec: ExecutionContext): Future[Something] =
    for {
      v1 <=: Future(someCalculation())
      v2 <=: Future(someOtherCalculation())
      v3 <=: Future(someDifferentCalculation())
    } yield doSomethingWith(v1, v2, v3)

There is no longer any doubt that the programmer intended for all 3 futures to run in parallel.

The macro would examine all of the for-expression's generators and expand consecutive expressions that use the <=: operator to a series of variable declarations using the = operator followed by a series of assignments using the <- operator, exactly as we saw earlier:

 def doSomething(someParameter: SomeType)
                (implicit ec: ExecutionContext): Future[Something] =
   for {
     f1 = Future(someCalculation())
     f2 = Future(someOtherCalculation())
     f3 = Future(someDifferentCalculation())
     v1 <- f1
     v2 <- f2
     v3 <- f3
   } yield doSomethingWith(v1, v2, v3)

What's more, because the compiler 'knows' that the programmer's intention was to run the Futures in parallel, this sort of error could cause an error or warning message to be generated:

 def doSomething(someParameter: SomeType)
                (implicit ec: ExecutionContext): Future[Something] =
   for {
     v1 <=: Future(someCalculation())
     x <- List(1, 2, 3)
     v2 <=: Future(someOtherCalculation())
     y <- List("a", "b")
     v3 <=: Future(someDifferentCalculation())
   } yield doSomethingWith(v1, v2, v3)
 

... or the macro might reorder the generators and issue a warning that it did so.

Include the Macro in Scala 2.12.x

This macro should become part of the Scala language so long as Futures are part of the standard runtime. If and when Futures are hived out of the standard runtime, the macro should be packaged with Futures.


PS: @flaviowbrasil tweeted: "Easily doable with a macro transformation. In fact, I've implemented this transformation at Twitter, but it's not open source."


Contact Mike Slinn

Unless you are a recruiter, in which case you should not try to make contact!

  • Email
  • Direct: 514-418-0156
  • Mobile: 650-678-2285

Disclaimer

The content on this web site is provided for general information purposes only and does not constitute legal or other professional advice or an opinion of any kind. Users of this web site are advised to seek specific legal advice by contacting their own legal counsel regarding any specific legal issues. Michael Slinn does not warrant or guarantee the quality, accuracy or completeness of any information on this web site. The articles published on this web site are current as of their original date of publication, but should not be relied upon as accurate, timely or fit for any particular purpose.

Accessing or using this web site does not create a client relationship. Although your use of the web site may facilitate access to or communications with Michael Slinn via e-mail or otherwise via the web site, receipt of any such communications or transmissions does not create a client relationship. Michael Slinn does not guarantee the security or confidentiality of any communications made by e-mail or otherwise through this web site.

This web site may contain links to third party web sites. Monitoring the vast information disseminated and accessible through those links is beyond Michael Slinn's resources and he does not attempt to do so. Links are provided for convenience only and Michael Slinn does not endorse the information contained in linked web sites nor guarantee its accuracy, timeliness or fitness for a particular purpose.


comments powered by Disqus

© 1976-2020, Michael Slinn. All rights reserved.