Home > other >  How to handle tail recursion with futures
How to handle tail recursion with futures

Time:10-22

Consider the following example

  def futureFoo() = {
    Future.successful(true)
  }

  def recFoo(x: List[Int]): Unit = {
    if (x.isEmpty) return

    for {
      b <- futureFoo()
      v = getNewListOfValues(x.last)
      _ = recFoo(v)
    } yield b
  }

I need to wait for futureFoo to finish and only then call recFoo again. The problem is no matter what I try I get the following error:

discarded non-Unit value

I also tried to convert it into a while loop but because of the future I either get the same error or the while condition doesn't update because it must be updated in a for comprehension or map.

Any ideas on how to prevent that error?

CodePudding user response:

Try this.

def recFoo(x: List[Int]): Unit =
  if (x.nonEmpty)
    futureFoo().foreach(_ => recFoo(getNewListOfValues(x.last)))

CodePudding user response:

The specific reason that you are getting

discarded non-Unit value

in your error message is that you have an expression after return.

Note that in Scala, the return keyword should almost never be used. Scala is an expression-oriented language; each block (such as a function body) evaluates to the value returned from the last line in the block.

So, for example, consider the following snippet:

val foo = {
  import scala.util.Random
  if (Random.nextInt() % 2 == 0) {
    17
  } else {
    "bar"
  }
}

Everything from if to the closing brace after "bar" is a single expression -- NOT a statement. Scala, in face, does not have "if-statements" in the way that Java and other languages do. In particular, the compiler needs to infer a type for the name foo, and since foo could concretely be either the Int 17 or the String "bar", that inferred type is the closest common ancestor of both Int and String, which is Any.

In your question, the last expression in the body of recFoo is the following:

for {
  b <- futureFoo()
  v = getNewListOfValues(x.last)
  _ = recFoo(v)
} yield b

What is the type of this expression? In many languages, for introduces a statement, but that's not true of Scala -- this is an expression, not a statement, and like all expressions it will have a value once we evaluate it. That value has type Future[Unit], and like all non-Unit values, the compiler is warning you that you are discarding a value, which is (almost) always a mistake. (Why would you go to the trouble of producing a non-Unit value and then not make use of it?, goes the thinking.)

  • Related