简体   繁体   中英

Scala Future return Type

I have the following lines of code...

val a = Future { Thread.sleep(10*1000); 42 }
val b = a.map(_ * 2)

After sometime when I check the value of b, I have the following getting printed.

scala.concurrent.Future[Int] = Future(Success(84))

Above, b's type is Future[Int]; but in the documentation, it says Future's apply method always returns Future(Try[T]). The documentation and the above example contradict. Can someone please help.

Please post your imports and the documentation you have referenced.

I think best parallel to understanding this is:

Try[T] is like Option[T] , Try[T] is always Success[T](value: T) or Failure[T](exception: Throwable) , just like Option[T] is always Some[T](value: T) or None

It can also be helpful to use the Scala REPL for things like this. It allows you to easily see types.

I'm assuming you've done this:

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> import scala.util.{Failure, Success}
import scala.util.{Failure, Success}

Now you have your two lines:

scala> val a = Future { Thread.sleep(10*1000); 42 }
val a: scala.concurrent.Future[Int] = Future(<not completed>)

scala> val b = a.map(_ * 2)
val b: scala.concurrent.Future[Int] = Future(<not completed>)

As you can see the type of b is still of scala.concurrent.Future[Int] as it maps the result of a , an Int , which happens to be 42 , using the function (_: Int -> _ * 2):Int .

And eventually:

scala> b
val res0: scala.concurrent.Future[Int] = Future(Success(84))

From this documentation of Scala Future s :

Notice that the 84 you expected is wrapped in a Success , which is further wrapped in a Future . This is a key point to know: The value in a Future is always an instance of one of the Try types: Success or Failure . Therefore, when working with the result of a future, use the usual Try -handling techniques, or one of the other Future callback methods.

Finally, to extract the Try from the future, either a Success or a Failure , from which we will get our result, or an error:

scala> b.onComplete {
     |     case Success(value) => println(s"Got the callback, value = $value")
     |     case Failure(e) => e.printStackTrace
     | }
Got the callback, value = 84

You are mixing two things here. When you create a Future , it is created using the apply function which is in the companion object of Future :

def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] =
    unit.map(_ => body)

So as long as the future is not completed, its type is Future[Int] . Once the future completes, the result type will be Future[Try[Int]] .

As stated on onComplete documentation:

When this future is completed, either through an exception, or a value, apply the provided function.

Therefore when you printed the completed future, it already had the Success. If you will do the same experiment with a longer wait, and an uncompleted future you will see that its type is not yet success.

For example, the following code:

implicit val ec = scala.concurrent.ExecutionContext.global
val a = Future { Thread.sleep(10*1000); 42 }
println(a)
Await.result(a, Integer.MAX_VALUE.seconds)
println(a)

will output:

Future(<not completed>)
Future(Success(42))

You can see that example running here .

Let's now look at onComplete . The following code:

val a = Future { Thread.sleep(10*1000); 42 }
a.onComplete {
  case Success(value) =>
    println(value)
  case Failure(exception) =>
    println(exception)
}

val b = Future { throw new RuntimeException }
b.onComplete {
  case Success(value) =>
    println(value)
  case Failure(exception) =>
    println(exception)
}

Await.result(a, Integer.MAX_VALUE.seconds)
Await.result(b, Integer.MAX_VALUE.seconds)

Here we can see an example how to use onComplete when a should complete successfully, and b should throw, and this is exactly what we get. The output is:

java.lang.RuntimeException
42

Because the throwingFuture is completed first, it is printed first.

The documentation says that a Future[B] contains a Try[B] , which is correct. I think you're getting confused by the toString representation here: Future(Success(84)) is the textual representation of a Future[Int] . For a Future[Try[Int]] , you would have Future(Success(Success(84))) as the textual representation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM