Accessing value returned by scala futures

ScalaFuture

Scala Problem Overview


I am a newbie to scala futures and I have a doubt regarding the return value of scala futures.

So, generally syntax for a scala future is

 def downloadPage(url: URL) = Future[List[Int]] {

 }

I want to know how to access the List[Int] from some other method which calls this method.

In other words,

val result = downloadPage("localhost") 

then what should be the approach to get List[Int] out of the future ?

I have tried using map method but not able to do this successfully.`

Scala Solutions


Solution 1 - Scala

> The case of Success(listInt) => I want to return the listInt and I am not able to figure out how to do that.

The best practice is that you don't return the value. Instead you just pass the future (or a version transformed with map, flatMap, etc.) to everyone who needs this value and they can add their own onComplete.

If you really need to return it (e.g. when implementing a legacy method), then the only thing you can do is to block (e.g. with Await.result) and you need to decide how long to await.

Solution 2 - Scala

You need to wait for the future to complete to get the result given some timespan, here's something that would work:

  import scala.concurrent.duration._
  
  def downloadPage(url: URL) = Future[List[Int]] {
    List(1,2,3)
  }
  
  val result = downloadPage("localhost")
  
  val myListInt = result.result(10 seconds)

Ideally, if you're using a Future, you don't want to block the executing thread, so you would move your logic that deals with the result of your Future into the onComplete method, something like this:

  result.onComplete({
    case Success(listInt) => {
      //Do something with my list
    }
    case Failure(exception) => {
      //Do something with my error
    }
  })

Solution 3 - Scala

I hope you already solved this since it was asked in 2013 but maybe my answer can help someone else:

If you are using Play Framework, it support async Actions (actually all Actions are async inside). An easy way to create an async Action is using Action.async(). You need to provide a Future[Result]to this function.

Now you can just make transformations from your Future[List[Int]] to Future[Result] using Scala's map, flatMap, for-comprehension or async/await. Here an example from Play Framework documentation.

import play.api.libs.concurrent.Execution.Implicits.defaultContext

def index = Action.async {
  val futureInt = scala.concurrent.Future { intensiveComputation() }
  futureInt.map(i => Ok("Got result: " + i))
}

Solution 4 - Scala

You can do something like that. If The wait time that is given in Await.result method is less than it takes the awaitable to execute, you will have a TimeoutException, and you need to handle the error (or any other error).

import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
import scala.concurrent.duration._

object MyObject {
    def main(args: Array[String]) {

        val myVal: Future[String] = Future { silly() }

        // values less than 5 seconds will go to 
        // Failure case, because silly() will not be done yet
        Try(Await.result(myVal, 10 seconds)) match {
            case Success(extractedVal) => { println("Success Happened: " + extractedVal) }
            case Failure(_) => { println("Failure Happened") }
            case _ => { println("Very Strange") }
        }      
    }

    def silly(): String = {
        Thread.sleep(5000)
        "Hello from silly"
        }
}

Solution 5 - Scala

The best way I’ve found to think of a Future is a box that will, at some point, contain the thing that you want. The key thing with a Future is that you never open the box. Trying to force open the box will lead you to blocking and grief. Instead, you put the Future in another, larger box, typically using the map method.

Here’s an example of a Future that contains a String. When the Future completes, then Console.println is called:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object Main {

  def main(args:Array[String]) : Unit = {
    val stringFuture: Future[String] = Future.successful("hello world!")
    stringFuture.map {
      someString =>
        // if you use .foreach you avoid creating an extra Future, but we are proving
        // the concept here...
        Console.println(someString)
    }
  }
}

Note that in this case, we’re calling the main method and then… finishing. The string’s Future, provided by the global ExecutionContext, does the work of calling Console.println. This is great, because when we give up control over when someString is going to be there and when Console.println is going to be called, we let the system manage itself. In constrast, look what happens when we try to force the box open:

val stringFuture: Future[String] = Future.successful("hello world!")
val someString = Future.await(stringFuture)

In this case, we have to wait — keep a thread twiddling its thumbs — until we get someString back. We’ve opened the box, but we’ve had to commandeer the system’s resources to get at it.

Solution 6 - Scala

It wasn't yet mentioned, so I want to emphasize the point of using Future with for-comprehension and the difference of sequential and parallel execution.

For example, for sequential execution:

object FuturesSequential extends App {

  def job(n: Int) = Future {
    Thread.sleep(1000)
    println(s"Job $n")
  }

  val f = for {
    f1 <- job(1)
    f2 <- job(2)
    f3 <- job(3)
    f4 <- job(4)
    f5 <- job(5)
  } yield List(f1, f2, f3, f4, f5)
  f.map(res => println(s"Done. ${res.size} jobs run"))
  Thread.sleep(6000) // We need to prevent main thread from quitting too early
}

And for parallel execution (note that the Future are before the for-comprehension):

object FuturesParallel extends App {

  def job(n: Int) = Future {
    Thread.sleep(1000)
    println(s"Job $n")
  }

  val j1 = job(1)
  val j2 = job(2)
  val j3 = job(3)
  val j4 = job(4)
  val j5 = job(5)

  val f = for {
    f1 <- j1
    f2 <- j2
    f3 <- j3
    f4 <- j4
    f5 <- j5
  } yield List(f1, f2, f3, f4, f5)
  f.map(res => println(s"Done. ${res.size} jobs run"))
  Thread.sleep(6000) // We need to prevent main thread from quitting too early
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1822249View Question on Stackoverflow
Solution 1 - ScalaAlexey RomanovView Answer on Stackoverflow
Solution 2 - ScalaNoahView Answer on Stackoverflow
Solution 3 - ScalajfuentesView Answer on Stackoverflow
Solution 4 - ScalaAkavallView Answer on Stackoverflow
Solution 5 - ScalaPriyank DesaiView Answer on Stackoverflow
Solution 6 - ScalaJohnnyView Answer on Stackoverflow