Scala with cats IO/Either instead of Future/Exceptions - scala

I'm in the process of adopting IO/Either to replace Future/Exception's where applicable, but I need help with the following code:
// some Java library
def dbLoad(id: Int): Int = {
throw new Exception("db exception")
}
// my scala code
sealed trait DbError extends Exception with Product
object DbError {
case object SomeError extends DbError
}
val load: Int => IO[Either[DbError, Int]] = { id =>
IO.fromFuture { IO { Future {
try { Right(dbLoad(id)) } catch { case NonFatal(e) => Left(SomeError) }
} } }
}
val loadAll: IO[Either[DbError, (Int, Int, Int)]] =
for {
i1 <- load(1)
i2 <- // call 'load' passing i1 as parameter, if i1 is 'right'
i3 <- // call 'load' passing i2 as parameter, if i2 is 'right'
} yield (i1, i2, i3) match {
case (Right(i1), Right(i2), Right(i3)) => Right((i1, i2, i3))
case _ => Left(SomeError)
}
I have not been able to get it working/compiling correctly, could you please help me understand:
how can I avoid executing subsequent calls to load (in loadAll) if a Left is detected?
if a call to load is successful, how can I use its right value for the following call to load?
is this the right approach to do it? Would you implement it in a different way?
Thanks everyone

Let me first put up the code that I think gets you what you want, and how typically things like this might be approached, I'll then describe what and why, and maybe some other suggestions:
import cats.data.EitherT
import cats.effect.IO
import cats.implicits._
import com.example.StackOverflow.DbError.SomeError
import scala.concurrent.Future
import scala.util.control.NonFatal
import scala.concurrent.ExecutionContext.Implicits.global
object StackOverflow {
// some Java library
def dbLoad(id: Int): Int = {
throw new Exception("db exception")
}
// my scala code
sealed trait DbError extends Exception with Product
object DbError {
case object SomeError extends DbError
}
val load: Int => IO[Either[DbError, Int]] = { id =>
IO.fromFuture(
IO(
Future(dbLoad(id))
.map(Right(_))
.recover {
case NonFatal(_) => Left(SomeError)
}
)
)
}
val loadAll: EitherT[IO, DbError, (Int, Int, Int)] =
for {
i1 <- EitherT(load(1))
i2 <- EitherT(load(i1))
i3 <- EitherT(load(i2))
} yield (i1, i2, i3)
val x: IO[Either[DbError, (Int, Int, Int)]] = loadAll.value
}
First, rather than try-catch inside the IO[Future[_]], Future itself has a number of combinators that can help you manage errors, assuming you have some control over what you get back.
For-comprehensions in Scala when applied in this fashion "short circuit" so if the first call to load(1) fails with a left then the rest of the comprehension won't execute. The use of EitherT allows you to manage the fact that your Either is "wrapped" in an effect type.
There are some problems with this approach, specifically around variance, you can read about them here:
http://www.beyondthelines.net/programming/the-problem-with-eithert/
There are also some performance implications for using this pattern that you may want to consider

Related

First click on button has an odd behaviour

I am working on a todo list app using
scalajs,
cats (free monads), and
scalajs-react
When I am using a simple model like the code below, everything works like expected.
class TodoModel() {
private object State {
var todos = Seq.empty[Todo]
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
}
}
def add(t: Todo): Callback = State.mod(_ :+ t)
def todos: Seq[Todo] = State.todos
}
Once I use the free monads from cats, I have an odd behaviour. The first click always inserts two todo entries. Every click afterwards works like expected. See the pictures below.
What is wrong here?
import cats.free.Free
import cats.free.Free.liftF
import japgolly.scalajs.react._
import japgolly.scalajs.react.vdom.html_<^._
import org.scalajs.dom
case class Todo(text: String)
sealed trait TodoModelOp[A]
case class Add(todo: Todo) extends TodoModelOp[Unit]
case class Todos() extends TodoModelOp[Seq[Todo]]
object FreeTodoModelOps {
// type alias for lifted TodoModelOp
type TodoModelOpF[A] = Free[TodoModelOp, A]
def add(Todo: Todo): TodoModelOpF[Unit] = liftF[TodoModelOp, Unit](Add(Todo))
def todos: TodoModelOpF[Seq[Todo]] = liftF[TodoModelOp, Seq[Todo]](Todos())
}
object StateInterpreter {
import cats.arrow.FunctionK
import cats.{ Id, ~> }
val interpet: TodoModelOp ~> Id = new (TodoModelOp ~> Id) {
val todos = scala.collection.mutable.ArrayBuffer.empty[Todo]
def apply[A](fa: TodoModelOp[A]): Id[A] = fa match {
case Add(todo) => todos += todo; ()
case Todos() => todos.toSeq
}
}
}
class TodoModel() {
import cats.instances.list._
import cats.syntax.traverse._
import FreeTodoModelOps._
def add(t: Todo): Callback = {
def program: TodoModelOpF[Unit] = for {
_ <- FreeTodoModelOps.add(t)
} yield ()
Callback(program.foldMap(StateInterpreter.interpet))
}
def todos: Seq[Todo] = {
def program: TodoModelOpF[Seq[Todo]] = for {
n <- FreeTodoModelOps.todos
} yield n
program.foldMap(StateInterpreter.interpet)
}
}
object TodoPage {
case class Props(model: TodoModel)
case class State(todos: Seq[Todo])
class Backend($: BackendScope[Props, State]) {
val t = Todo("a new todo")
def onSubmit(e: ReactEventFromInput) =
e.preventDefaultCB >>
$.modState(s => State(s.todos :+ t)) >>
$.props.flatMap(P => P.model.add(t))
def render(S: State) =
<.div(
<.form(
^.onSubmit ==> onSubmit,
<.button("Add #", S.todos.length + 1)),
<.ul(S.todos.map(t => <.li(t.text)): _*))
}
val component = ScalaComponent.builder[Props]("Todo")
.initialStateFromProps(p => State(p.model.todos))
.renderBackend[Backend]
.build
def apply(model: TodoModel) = component(Props(model))
}
object Test {
val model = new TodoModel()
def main(args: Array[String]): Unit = {
TodoPage.apply(model).renderIntoDOM(dom.document.getElementById("mount-node"))
}
}
empty, no click on button
first click on button
second click on button
In your first snippet there's a bug:
Here you've got a variable todos (inpure) which you're accessing in a pure context:
def mod(f: Seq[Todo] => Seq[Todo]): Callback = {
val newTodos = f(todos)
Callback(todos = newTodos)
Impurity should be in Callback. Even reading a variable outside of a Callback is unsafe, so it should be:
def mod(f: Seq[Todo] => Seq[Todo]): Callback =
Callback(todos = f(todos))
(See scalajs-react's Ref.scala an example of safely working with a variable.)
Secondly, with regards to your larger snippet, scalajs-react is very FP friendly but that's very unconventional way of trying to use it, and has some significant problems:
StateInterpreter.interpet isn't referentially-transparent; there's shared global state underlying that. Fails the FP test. Stops being a lawful natural transformation.
You're tracking two sets of identical state separately: the component state and the state in TodoModel (impure, fails the FP test). Not only is this approach redundant and runs the risk of the two states getting out-of-sync, but it also makes the component less reusable; imagine you decided to draw it twice on the same screen for the same data - they're going to go out of sync. Best to keep the component stateless and pure.
If you're going to transform a free structure into a component effect, it's best to transform it into a state monad, see here for an example.
It's really, really awesome that you're learning about free monads and scalajs-react. FP will make your entire program really, really easy to reason about and prevent confusing surprises in behaviour, but you've got to not cut any corners and make sure that you keep all of your code pure. Any impurity will render the entire stack all the way up to the entrypoint impure and remove those nice dependable FP properties from those layers. I'd suggest making everything as pure as possible using the points above as starting points, and then I think you'll find that the bug just disappears, or at least is very easy to then detect. Cheers

Iterate data source asynchronously in batch and stop while remote return no data in Scala

Let's say we have a fake data source which will return data it holds in batch
class DataSource(size: Int) {
private var s = 0
implicit val g = scala.concurrent.ExecutionContext.global
def getData(): Future[List[Int]] = {
s = s + 1
Future {
Thread.sleep(Random.nextInt(s * 100))
if (s <= size) {
List.fill(100)(s)
} else {
List()
}
}
}
object Test extends App {
val source = new DataSource(100)
implicit val g = scala.concurrent.ExecutionContext.global
def process(v: List[Int]): Unit = {
println(v)
}
def next(f: (List[Int]) => Unit): Unit = {
val fut = source.getData()
fut.onComplete {
case Success(v) => {
f(v)
v match {
case h :: t => next(f)
}
}
}
}
next(process)
Thread.sleep(1000000000)
}
I have mine, the problem here is some portion is more not pure. Ideally, I would like to wrap the Future for each batch into a big future, and the wrapper future success when last batch returned 0 size list? My situation is a little from this post, the next() there is synchronous call while my is also async.
Or is it ever possible to do what I want? Next batch will only be fetched when the previous one is resolved in the end whether to fetch the next batch depends on the size returned?
What's the best way to walk through this type of data sources? Are there any existing Scala frameworks that provide the feature I am looking for? Is play's Iteratee, Enumerator, Enumeratee the right tool? If so, can anyone provide an example on how to use those facilities to implement what I am looking for?
Edit----
With help from chunjef, I had just tried out. And it actually did work out for me. However, there was some small change I made based on his answer.
Source.fromIterator(()=>Iterator.continually(source.getData())).mapAsync(1) (f=>f.filter(_.size > 0))
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runForeach(println)
However, can someone give comparison between Akka Stream and Play Iteratee? Does it worth me also try out Iteratee?
Code snip 1:
Source.fromIterator(() => Iterator.continually(ds.getData)) // line 1
.mapAsync(1)(identity) // line 2
.takeWhile(_.nonEmpty) // line 3
.runForeach(println) // line 4
Code snip 2: Assuming the getData depends on some other output of another flow, and I would like to concat it with the below flow. However, it yield too many files open error. Not sure what would cause this error, the mapAsync has been limited to 1 as its throughput if I understood correctly.
Flow[Int].mapConcat[Future[List[Int]]](c => {
Iterator.continually(ds.getData(c)).to[collection.immutable.Iterable]
}).mapAsync(1)(identity).takeWhile(_.nonEmpty).runForeach(println)
The following is one way to achieve the same behavior with Akka Streams, using your DataSource class:
import scala.concurrent.Future
import scala.util.Random
import akka.actor.ActorSystem
import akka.stream._
import akka.stream.scaladsl._
object StreamsExample extends App {
implicit val system = ActorSystem("Sandbox")
implicit val materializer = ActorMaterializer()
val ds = new DataSource(100)
Source.fromIterator(() => Iterator.continually(ds.getData)) // line 1
.mapAsync(1)(identity) // line 2
.takeWhile(_.nonEmpty) // line 3
.runForeach(println) // line 4
}
class DataSource(size: Int) {
...
}
A simplified line-by-line overview:
line 1: Creates a stream source that continually calls ds.getData if there is downstream demand.
line 2: mapAsync is a way to deal with stream elements that are Futures. In this case, the stream elements are of type Future[List[Int]]. The argument 1 is the level of parallelism: we specify 1 here because DataSource internally uses a mutable variable, and a parallelism level greater than one could produce unexpected results. identity is shorthand for x => x, which basically means that for each Future, we pass its result downstream without transforming it.
line 3: Essentially, ds.getData is called as long as the result of the Future is a non-empty List[Int]. If an empty List is encountered, processing is terminated.
line 4: runForeach here takes a function List[Int] => Unit and invokes that function for each stream element.
Ideally, I would like to wrap the Future for each batch into a big future, and the wrapper future success when last batch returned 0 size list?
I think you are looking for a Promise.
You would set up a Promise before you start the first iteration.
This gives you promise.future, a Future that you can then use to follow the completion of everything.
In your onComplete, you add a case _ => promise.success().
Something like
def loopUntilDone(f: (List[Int]) => Unit): Future[Unit] = {
val promise = Promise[Unit]
def next(): Unit = source.getData().onComplete {
case Success(v) =>
f(v)
v match {
case h :: t => next()
case _ => promise.success()
}
case Failure(e) => promise.failure(e)
}
// get going
next(f)
// return the Future for everything
promise.future
}
// future for everything, this is a `Future[Unit]`
// its `onComplete` will be triggered when there is no more data
val everything = loopUntilDone(process)
You are probably looking for a reactive streams library. My personal favorite (and one I'm most familiar with) is Monix. This is how it will work with DataSource unchanged
import scala.concurrent.duration.Duration
import scala.concurrent.Await
import monix.reactive.Observable
import monix.execution.Scheduler.Implicits.global
object Test extends App {
val source = new DataSource(100)
val completed = // <- this is Future[Unit], completes when foreach is done
Observable.repeat(Observable.fromFuture(source.getData()))
.flatten // <- Here it's Observable[List[Int]], it has collection-like methods
.takeWhile(_.nonEmpty)
.foreach(println)
Await.result(completed, Duration.Inf)
}
I just figured out that by using flatMapConcat can achieve what I wanted to achieve. There is no point to start another question as I have had the answer already. Put my sample code here just in case someone is looking for similar answer.
This type of API is very common for some integration between traditional Enterprise applications. The DataSource is to mock the API while the object App is to demonstrate how the client code can utilize Akka Stream to consume the APIs.
In my small project the API was provided in SOAP, and I used scalaxb to transform the SOAP to Scala async style. And with the client calls demonstrated in the object App, we can consume the API with AKKA Stream. Thanks for all for the help.
class DataSource(size: Int) {
private var transactionId: Long = 0
private val transactionCursorMap: mutable.HashMap[TransactionId, Set[ReadCursorId]] = mutable.HashMap.empty
private val cursorIteratorMap: mutable.HashMap[ReadCursorId, Iterator[List[Int]]] = mutable.HashMap.empty
implicit val g = scala.concurrent.ExecutionContext.global
case class TransactionId(id: Long)
case class ReadCursorId(id: Long)
def startTransaction(): Future[TransactionId] = {
Future {
synchronized {
transactionId += transactionId
}
val t = TransactionId(transactionId)
transactionCursorMap.update(t, Set(ReadCursorId(0)))
t
}
}
def createCursorId(t: TransactionId): ReadCursorId = {
synchronized {
val c = transactionCursorMap.getOrElseUpdate(t, Set(ReadCursorId(0)))
val currentId = c.foldLeft(0l) { (acc, a) => acc.max(a.id) }
val cId = ReadCursorId(currentId + 1)
transactionCursorMap.update(t, c + cId)
cursorIteratorMap.put(cId, createIterator)
cId
}
}
def createIterator(): Iterator[List[Int]] = {
(for {i <- 1 to 100} yield List.fill(100)(i)).toIterator
}
def startRead(t: TransactionId): Future[ReadCursorId] = {
Future {
createCursorId(t)
}
}
def getData(cursorId: ReadCursorId): Future[List[Int]] = {
synchronized {
Future {
Thread.sleep(Random.nextInt(100))
cursorIteratorMap.get(cursorId) match {
case Some(i) => i.next()
case _ => List()
}
}
}
}
}
object Test extends App {
val source = new DataSource(10)
implicit val system = ActorSystem("Sandbox")
implicit val materializer = ActorMaterializer()
implicit val g = scala.concurrent.ExecutionContext.global
//
// def process(v: List[Int]): Unit = {
// println(v)
// }
//
// def next(f: (List[Int]) => Unit): Unit = {
// val fut = source.getData()
// fut.onComplete {
// case Success(v) => {
// f(v)
// v match {
//
// case h :: t => next(f)
//
// }
// }
//
// }
//
// }
//
// next(process)
//
// Thread.sleep(1000000000)
val s = Source.fromFuture(source.startTransaction())
.map { e =>
source.startRead(e)
}
.mapAsync(1)(identity)
.flatMapConcat(
e => {
Source.fromIterator(() => Iterator.continually(source.getData(e)))
})
.mapAsync(5)(identity)
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runForeach(println)
/*
val done = Source.fromIterator(() => Iterator.continually(source.getData())).mapAsync(1)(identity)
.via(Flow[List[Int]].takeWhile(_.nonEmpty))
.runFold(List[List[Int]]()) { (acc, r) =>
// println("=======" + acc + r)
r :: acc
}
done.onSuccess {
case e => {
e.foreach(println)
}
}
done.onComplete(_ => system.terminate())
*/
}

Why does a Scala for-comprehension have to start with a generator?

According to the Scala Language Specification (ยง6.19), "An enumerator sequence always starts with a generator". Why?
I sometimes find this restriction to be a hindrance when using for-comprehensions with monads, because it means you can't do things like this:
def getFooValue(): Future[Int] = {
for {
manager = Manager.getManager() // could throw an exception
foo <- manager.makeFoo() // method call returns a Future
value = foo.getValue()
} yield value
}
Indeed, scalac rejects this with the error message '<-' expected but '=' found.
If this was valid syntax in Scala, one advantage would be that any exception thrown by Manager.getManager() would be caught by the Future monad used within the for-comprehension, and would cause it to yield a failed Future, which is what I want. The workaround of moving the call to Manager.getManager() outside the for-comprehension doesn't have this advantage:
def getFooValue(): Future[Int] = {
val manager = Manager.getManager()
for {
foo <- manager.makeFoo()
value = foo.getValue()
} yield value
}
In this case, an exception thrown by foo.getValue() will yield a failed Future (which is what I want), but an exception thrown by Manager.getManager() will be thrown back to the caller of getFooValue() (which is not what I want). Other possible ways of handling the exception are more verbose.
I find this restriction especially puzzling because in Haskell's otherwise similar do notation, there is no requirement that a do block should begin with a statement containing <-. Can anyone explain this difference between Scala and Haskell?
Here's a complete working example showing how exceptions are caught by the Future monad in for-comprehensions:
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
class Foo(val value: Int) {
def getValue(crash: Boolean): Int = {
if (crash) {
throw new Exception("failed to get value")
} else {
value
}
}
}
class Manager {
def makeFoo(crash: Boolean): Future[Foo] = {
if (crash) {
throw new Exception("failed to make Foo")
} else {
Future(new Foo(10))
}
}
}
object Manager {
def getManager(crash: Boolean): Manager = {
if (crash) {
throw new Exception("failed to get manager")
} else {
new Manager()
}
}
}
object Main extends App {
def getFooValue(crashGetManager: Boolean,
crashMakeFoo: Boolean,
crashGetValue: Boolean): Future[Int] = {
for {
manager <- Future(Manager.getManager(crashGetManager))
foo <- manager.makeFoo(crashMakeFoo)
value = foo.getValue(crashGetValue)
} yield value
}
def waitForValue(future: Future[Int]): Unit = {
val result = Try(Await.result(future, Duration("10 seconds")))
result match {
case Success(value) => println(s"Got value: $value")
case Failure(e) => println(s"Got error: $e")
}
}
val future1 = getFooValue(false, false, false)
waitForValue(future1)
val future2 = getFooValue(true, false, false)
waitForValue(future2)
val future3 = getFooValue(false, true, false)
waitForValue(future3)
val future4 = getFooValue(false, false, true)
waitForValue(future4)
}
Here's the output:
Got value: 10
Got error: java.lang.Exception: failed to get manager
Got error: java.lang.Exception: failed to make Foo
Got error: java.lang.Exception: failed to get value
This is a trivial example, but I'm working on a project in which we have a lot of non-trivial code that depends on this behaviour. As far as I understand, this is one of the main advantages of using Future (or Try) as a monad. What I find strange is that I have to write
manager <- Future(Manager.getManager(crashGetManager))
instead of
manager = Manager.getManager(crashGetManager)
(Edited to reflect #RexKerr's point that the monad is doing the work of catching the exceptions.)
for comprehensions do not catch exceptions. Try does, and it has the appropriate methods to participate in for-comprehensions, so you can
for {
manager <- Try { Manager.getManager() }
...
}
But then it's expecting Try all the way down unless you manually or implicitly have a way to switch container types (e.g. something that converts Try to a List).
So I'm not sure your premises are right. Any assignment you made in a for-comprehension can just be made early.
(Also, there is no point doing an assignment inside a for comprehension just to yield that exact value. Just do the computation in the yield block.)
(Also, just to illustrate that multiple types can play a role in for comprehensions so there's not a super-obvious correct answer for how to wrap an early assignment in terms of later types:
// List and Option, via implicit conversion
for {i <- List(1,2,3); j <- Option(i).filter(_ <2)} yield j
// Custom compatible types with map/flatMap
// Use :paste in the REPL to define A and B together
class A[X] { def flatMap[Y](f: X => B[Y]): A[Y] = new A[Y] }
class B[X](x: X) { def map[Y](f: X => Y): B[Y] = new B(f(x)) }
for{ i <- (new A[Int]); j <- (new B(i)) } yield j.toString
Even if you take the first type you still have the problem of whether there is a unique "bind" (way to wrap) and whether to doubly-wrap things that are already the correct type. There could be rules for all these things, but for-comprehensions are already hard enough to learn, no?)
Haskell translates the equivalent of for { manager = Manager.getManager(); ... } to the equivalent of lazy val manager = Manager.getManager(); for { ... }. This seems to work:
scala> lazy val x: Int = throw new Exception("")
x: Int = <lazy>
scala> for { y <- Future(x + 1) } yield y
res8: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#fedb05d
scala> Try(Await.result(res1, Duration("10 seconds")))
res9: scala.util.Try[Int] = Failure(java.lang.Exception: )
I think the reason this can't be done is because for-loops are syntactic sugar for flatMap and map methods (except if you are using a condition in the for-loop, in that case it's desugared with the method withFilter). When you are storing in a immutable variable, you can't use these methods. That's the reason you would be ok using Try as pointed out by Rex Kerr. In that case, you should be able to use map and flatMap methods.

waiting for "recursive" futures in scala

a simple code sample that describes my problem:
import scala.util._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
class LoserException(msg: String, dice: Int) extends Exception(msg) { def diceRoll: Int = dice }
def aPlayThatMayFail: Future[Int] = {
Thread.sleep(1000) //throwing a dice takes some time...
//throw a dice:
(1 + Random.nextInt(6)) match {
case 6 => Future.successful(6) //I win!
case i: Int => Future.failed(new LoserException("I did not get 6...", i))
}
}
def win(prefix: String): String = {
val futureGameLog = aPlayThatMayFail
futureGameLog.onComplete(t => t match {
case Success(diceRoll) => "%s, and finally, I won! I rolled %d !!!".format(prefix, diceRoll)
case Failure(e) => e match {
case ex: LoserException => win("%s, and then i got %d".format(prefix, ex.diceRoll))
case _: Throwable => "%s, and then somebody cheated!!!".format(prefix)
}
})
"I want to do something like futureGameLog.waitForRecursiveResult, using Await.result or something like that..."
}
win("I started playing the dice")
this simple example illustrates what i want to do. basically, if to put it in words, i want to wait for a result for some computation, when i compose different actions on previous success or failed attampts.
so how would you implement the win method?
my "real world" problem, if it makes any difference, is using dispatch for asynchronous http calls, where i want to keep making http calls whenever the previous one ends, but actions differ on wether the previous http call succeeded or not.
You can recover your failed future with a recursive call:
def foo(x: Int) = x match {
case 10 => Future.successful(x)
case _ => Future.failed[Int](new Exception)
}
def bar(x: Int): Future[Int] = {
foo(x) recoverWith { case _ => bar(x+1) }
}
scala> bar(0)
res0: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise#64d6601
scala> res0.value
res1: Option[scala.util.Try[Int]] = Some(Success(10))
recoverWith takes a PartialFunction[Throwable,scala.concurrent.Future[A]] and returns a Future[A]. You should be careful though, because it will use quite some memory when it does lots of recursive calls here.
As drexin answered the part about exception handling and recovering, let me try and answer the part about a recursive function involving futures. I believe using a Promise will help you achieve your goal. The restructured code would look like this:
def win(prefix: String): String = {
val prom = Promise[String]()
def doWin(p:String) {
val futureGameLog = aPlayThatMayFail
futureGameLog.onComplete(t => t match {
case Success(diceRoll) => prom.success("%s, and finally, I won! I rolled %d !!!".format(prefix, diceRoll))
case Failure(e) => e match {
case ex: LoserException => doWin("%s, and then i got %d".format(prefix, ex.diceRoll))
case other => prom.failure(new Exception("%s, and then somebody cheated!!!".format(prefix)))
}
})
}
doWin(prefix)
Await.result(prom.future, someTimeout)
}
Now this won't be true recursion in the sense that it will be building up one long stack due to the fact that the futures are async, but it is similar to recursion in spirit. Using the promise here gives you something to block against while the recursion does it's thing, blocking the caller from what's happening behind the scene.
Now, if I was doing this, I would probable redefine things like so:
def win(prefix: String): Future[String] = {
val prom = Promise[String]()
def doWin(p:String) {
val futureGameLog = aPlayThatMayFail
futureGameLog.onComplete(t => t match {
case Success(diceRoll) => prom.success("%s, and finally, I won! I rolled %d !!!".format(prefix, diceRoll))
case Failure(e) => e match {
case ex: LoserException => doWin("%s, and then i got %d".format(prefix, ex.diceRoll))
case other => prom.failure(new Exception("%s, and then somebody cheated!!!".format(prefix)))
}
})
}
doWin(prefix)
prom.future
}
This way you can defer the decision on whether to block or use async callbacks to the caller of this function. This is more flexible, but it also exposes the caller to the fact that you are doing async computations and I'm not sure that is going to be acceptable for your scenario. I'll leave that decision up to you.
This works for me:
def retryWithFuture[T](f: => Future[T],retries:Int, delay:FiniteDuration) (implicit ec: ExecutionContext, s: Scheduler): Future[T] ={
f.recoverWith { case _ if retries > 0 => after[T](delay,s)(retryWithFuture[T]( f , retries - 1 , delay)) }
}

Scala alternative to pythons `with`

In python you can avoid try {} catch {} finally {} boilerplate with with (see What is the python keyword "with" used for?). I remember seeing an alternative to that in Scala, but I can't find it anymore.
It goes along the lines of:
def using[O](r: {def close()})(doit: () => O): O = try {
doit()
} finally {
r.close
}
using(myWriter){() => myWriter.println("something or another")}
Is it built into 2.10, or do I need a separate library for it?
It's almost trivial to make your own that covers almost all use cases (here using 2.10):
implicit class TidyUpAnything[A](val a: A) extends AnyVal {
def tidily[Z](g: A=>Any)(f: A=>Z) = try { f(a) } finally { g(a) }
}
If you want exceptions to pass through, use as is:
scala> Option(null: String).tidily(println){_.get} // Should print None
None
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:313)
...
and if you want to handle exceptions, use it in conjunction with scala.util.Try:
scala> import scala.util._
scala> Try( Option(null: String).tidily(println){ _.get } )
None
res1: scala.util.Try[String] = Failure(java.util.NoSuchElementException: None.get)
Normally you would make g be something like _.close, but you can do arbitary resource cleanup with it. For example, here we back off a counter by one whenever we finish:
var i = 0
val a = Array(1,2)
a.tidily(_ => i -= 1){ _.foreach(_ => i += 1) }
scala> i
res2: Int = 1