Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Future that cannot fail in Scala

Tags:

scala

future

Is there the concept of a Future that cannot fail in Scala?

I'm transforming a Future[Result], which may fail—therefore I handle both a Failure and a Success—into a Future[Option[String]], carrying an optional error message derived from the failure or success states. So far, so good.

Thing is now, I would like to formally (i.e., with the help of the type system) remember that this future will always hold a Success and that I won't need to handle the failure case in the future.

Is there a smart way to do this?

like image 917
Jean-Philippe Pellet Avatar asked Mar 18 '16 12:03

Jean-Philippe Pellet


People also ask

How do you handle future Scala?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

What is future and promise in Scala?

The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.

Is future blocking onComplete?

NOTE: With Future. onComplete() we are no longer blocking for the result from the Future but instead we will receive a callback for either a Success or a Failure.


2 Answers

You cannot do that "with the help of type system" because there is no way for the type system to guarantee a Future will not fail, even if you promise that it won't.

Consider this:

 Future { doStuff(); }
   .recover { case _ => "Failed!" } // Now it always succeeds
   .map { _ => Seq.empty[String].head }  // Now it does not. 

Even if you were going to make any further transformations impossible, once the Future has been declared to always succeed, that still does not help, because the exception handler (or whatever you do to convert the original future to the "always succeeding one") could throw.

Update: as pointed out in a comment below, the code snippet above is incorrect: the result of .map is not the same Future as the result of .recover. The point stands however. Here is the correct illustration:

Future { doStuff }
  .recover { case _ => Seq.empty[String].head }
like image 149
Dima Avatar answered Oct 26 '22 23:10

Dima


Isn't this what type-tagging is for?

scala> type Tagged[U] = { type Tag = U }
defined type alias Tagged

scala> type @@[T, U] = T with Tagged[U]
defined type alias $at$at

scala> trait OK ; trait Uncertain
defined trait OK
defined trait Uncertain

scala> type Sure[A] = Future[A] @@ OK
defined type alias Sure

scala> type Unsure[A] = Future[A] @@ Uncertain
defined type alias Unsure

scala> val f = Future.successful(42).asInstanceOf[Sure[Int]]
f: Sure[Int] = Future(Success(42))

then

scala> object X { def p(f: Sure[_]) = "sure" ; def p(f: Unsure[_])(implicit d: DummyImplicit) = "unsure" }
defined object X

scala> X.p(f)
res1: String = sure

It doesn't remain sure under map, of course.

like image 45
som-snytt Avatar answered Oct 27 '22 00:10

som-snytt