#volatile var breakRequested: Boolean = false
// ...
def futureFunc(): Option[Iterable[String]] = {
val result = hugeList.map { item =>
if(breakRequested) {
// put exit code here
// return None
// throw AnException
// what else?
}
item.toText() // time-expensive function
}
Some(result)
}
Future { futureFunc() }
Given somebody set the breakRequested flag to true: How may I exit the map?
What I tried:
return None => such a return transformed into a scala.runtime.NonLocalReturnControl: I tried to catch this error, but it seems to be uncatchable (bypasses try/catch).
object Cancelled extends Exception: I tried to throw this but was not able to catch it as well.
All exceptions show up in the command line, when I run the app through SBT.
If somehow possible, I prefer a solution without try/catch.
For the fast solution, you can convert your hugeList to the Iterator, and then use takeWhile:
...
val result = hugeList.toIterator
.takeWhile(_ => !breakRequested)
.map { item =>
item.text
}
...
Edit:
Scala's Future has no cancellation, but twitter's Future has. To cancel this use method raise.
Also you can write your own map, for example:
#annotation.tailrec def map[T,R](
src: List[T],
cancel: => Boolean,
dsc: List[R] = List.empty[R])(f: T => R):List[R] = src match {
case _ if cancel => dsc
case h :: t => map(t, cancel, f(h) :: dsc)(f)
case Nil => dsc
}
Future{map(hugeList, breakRequested)(_.text)}
If you don't need the result, you can create another future,which will be completed after your breakRequested was changed. And use method Future.firstCompletedOf.
Related
I need to execute a Future method on some elements I have in a list simultaneously. My current implementation works sequentially, which is not optimal for saving time. I did this by mapping my list and calling the method on each element and processing the data this way.
My manager shared a link with me showing how to execute Futures simultaneously using for-comprehension but I cannot see/understand how I can implement this with my List.
The link he shared with me is https://alvinalexander.com/scala/how-use-multiple-scala-futures-in-for-comprehension-loop/
Here is my current code:
private def method1(id: String): Tuple2[Boolean, List[MyObject]] = {
val workers = List.concat(idleWorkers, activeWorkers.keys.toList)
var ready = true;
val workerStatus = workers.map{ worker =>
val option = Await.result(method2(worker), 1 seconds)
var status = if (option.isDefined) {
if (option.get._2 == id) {
option.get._1.toString
} else {
"INVALID"
}
} else "FAILED"
val status = s"$worker: $status"
if (option.get._1) {
ready = false
}
MyObject(worker.toString, status)
}.toList.filterNot(s => s. status.contains("INVALID"))
(ready, workerStatus)
}
private def method2(worker: ActorRef): Future[Option[(Boolean, String)]] = Future{
implicit val timeout: Timeout = 1 seconds;
Try(Await.result(worker ? GetStatus, 1 seconds)) match {
case Success(extractedVal) => extractedVal match {
case res: (Boolean, String) => Some(res)
case _ => None
}
case Failure(_) => { None }
case _ => { None }
}
}
If someone could suggest how to implement for-comprehension in this scenario, I would be grateful. Thanks
For method2 there is no need for the Future/Await mix. Just map the Future:
def method2(worker: ActorRef): Future[Option[(Boolean, String)]] =
(worker ? GetStatus).map{
case res: (Boolean, String) => Some(res)
case _ => None
}
For method1 you likewise need to map the result of method2 and do the processing inside the map. This will make workerStatus a List[Future[MyObject]] and means that everything runs in parallel.
Then use Future.sequence(workerStatus) to turn the List[Future[MyObject]] into a Future[List[MyObject]]. You can then use map again to do the filtering/ checking on that List[MyObject]. This will happen when all the individual Futures have completed.
Ideally you would then return a Future from method1 to keep everything asynchronous. You could, if absolutely necessary, use Await.result at this point which would wait for all the asynchronous operations to complete (or fail).
No need to pay attention to the purpose of the function here, it's only for demonstration:
def readAllByPersonOrFail(person: Person, otherPersonId: Long): Future[List[Person]] = {
val personSiblingsFuture: Future[List[Person]] = personSiblingsDomain.readAllByPersonId(person.id)
personSiblingsFuture.map { persons =>
persons.find(_.id == otherPersonId) match {
case Some(person) =>
person.isActive match {
case true => person
case false => throw new IllegalArgumentException("something inactive")
}
case None => throw new IllegalArgumentException("something wrong ehre")
}
}
personSiblingsFuture
}
I would like to return personSiblingsFuture above iff it validates (makes sure correct person is in the list and is active), otherwise throw the exception. I don't think the above code is doing the right thing as it is not existing upon failure.
Take a look at scala.concurrent.Future.map. This creates a new future, whose value is resolved by applying a function to the successful result of this future.
Note that here you're throwing away the resulting future you just created with .map() too.
There are a few areas to solve your problem, though you should question more deeply the use of exceptions with Futures. Scala provides concepts like Future, Option, and Try specifically to avoid throwing exceptions and have a clearer control flow.
Option 1, return the mapped future
In your funciton,
def func(...): Future[List[Person]] {
val personSiblingsFuture = ...;
personSiblingsFuture.map { persons =>
...
}
}
// note we're not returning personSiblingsFuture,
// but the mapped result
When someone actually tries to get the value of the future, e.g. by using .value, they might see an exception intead:
def main() {
val future = func(...); // this is fine
val my_list = future.value; // awaits Future, might throw here
}
Option 2, actually await the list and throw in the function
Returning a future that might throw is strange, it might be a bit easier if the you actually explicitly a had a function that might throw, e.g.
/** jsdoc describing function **/
def funcMightThrow(...): List[Person] {
val personSiblingsFuture = ...;
val personSiblings = personSiblingsFuture.value;
personSiblings.find(_.id == otherPersonId) match {
case Some(person) =>
person.isActive match {
case true => personSiblings
case false => throw new IllegalArgumentException("something inactive")
}
case None => throw new IllegalArgumentException("something wrong ehre")
}
}
Option 3, consider making return types more explicit
def func(...): Future[Try[List[Person]]] {
val personSiblingsFuture = ...;
personSiblingsFuture.map { persons =>
...
// successful case returns 'persons' (List[Person])
// fail cases return Failure(...) instead
}
} // return the mapped future
You can also return Try[List[Person]] rather than a Future[] of that, by using .value, which makes func a blocking function.
In a non-functional language, I might do something like:
try {
// some stuff
} catch Exception ex {
return false;
}
// Do more stuff
return true;
In Scala, however, this pattern is clearly not correct. If my scala code looks like this:
try {
// do some stuff
}
catch {
case e: Exception => // I want to get out of here and return false
)
}
// do more stuff
true
How do I properly do that? I don't want to use the "return" statement, of course, but I also don't want to drop through and "do more stuff" and eventually return true.
You want to represent a computation that can either succeed or signal that an error has occurred. That's the perfect use case for the Try monad.
import scala.util.{ Try, Success, Failure }
def myMethod: Try[Something] = Try {
// do stuff
// do more stuff
// if any exception occurs here, it gets wrapped into a Failure(e)
}
So you're returning a Try instead of a Bool, which is infinitely more clear and idiomatic.
Usage example:
myMethod match {
case Success(x) => println(s"computation succeded with result $x")
case Failure(e) => println(s"computation failed with exception $e.getMessage")
}
If you don't even care about the exception, but you just want to return a value in case of success, you can even convert the Try to an Option.
def myMethod: Option[Something] = Try {
// do stuff
// do more stuff
// return something
// if any exception occurs here, it gets wrapped into a Failure(e)
}.toOption
myMethod match {
case Some(x) => println(s"computation succeded with result $x")
case None => println("computation failed")
}
To respond to the question in the comments, you can do
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
// true
}
although I would suggest to return something more meaningful than a Boolean, whenever it makes sense.
Of course this can be nested
Try {
// do stuff
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
Try {
// something that can throw
} match {
case Failure(_) => false
case Success(_) =>
// do more stuff
true
}
}
but you should consider putting the Try chunks into separate functions (returning a Try).
Ultimately, we can take advantage of the fact that Try is a monad, and do something like this
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }.flatMap { _ =>
// do more stuff
Try { /* java code */ }
}
} match {
case Failure(_) => false // in case any of the Try blocks has thrown an Exception
case Success(_) => true // everything went smooth
}
scala> def f() = try { ??? ; 1 } catch { case _: Throwable => 2 }
f: ()Int
scala> f()
res2: Int = 2
scala> import util._
import util._
scala> def g() = Try { ??? ; 1 } recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
g: ()Int
scala> g()
res3: Int = 2
HTH. Small functions helps.
Another hint:
scala> def j() = Try (1) map (_ + 42) recover { case _ => 2 } get
warning: there was one feature warning; re-run with -feature for details
j: ()Int
scala> j()
res4: Int = 43
try-catch expression is not good for functional programming.
Anyway, an easy solution that still uses try-catch:
val result = try {
// do some stuff
Some(/* The final expression */)
}
catch {
case e: Exception => // Do something or nothing
None
}
result match {
case Some(r) => // Do something with r
true
case None => false
}
You can use scala.util.Try for cleaner and more functional-styled code.
Refer to https://codereview.stackexchange.com/questions/38689/code-with-many-early-returns-exits-into-the-functional-style
I faced a similar problem like you, but the answer in the Stackexchange CodeReview helped me a lot.
Successful or erroneous cases can be represented by several Scala type.
If you consider the error in the meaning of "something is missing" (e.g. file not found), you can use Option[T] (e.g. Option[File]), with case values None or Some(T). Then orElse, getOrElse or fold and map/flatMap functions can be used to dispatch cased.
You can also use Either[E, T], with (by convention), in Left(E) case the error value (e.g. a String as error message), and in Right(T) successful T value.
Monads Try[T] or Future[T] can be used in the same way.
In the field of I/O, the very nice scala-arm lib provide type ManagedResource[T] that wrap either successful (T) or erroneous (List[Throwable]]) result of computation based on resources.
Valudation types in Scalaz are also useful for such cases.
'util.Try{ do some stuff }.isSuccess'
I'm new to asynchronous programming. I read this tutorial http://danielwestheide.com/blog/2013/01/09/the-neophytes-guide-to-scala-part-8-welcome-to-the-future.html and was surprised by how effortless I can incorporate Future into the program. However, when I was using Future with Routing, the return type is kind of wrong.
get {
optionalCookie("commToken") {
case Some(commCookie) =>
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
val result = Await.result(response, 5 seconds)
setCookie(HttpCookie("commToken", content = result._2.mturker.get.commToken)) {
complete(result._1, result._2.mturker.get)
}
case None => // ...
}
}
I really don't want to use Await (what's the point of asynchronous if I just block the thread and wait for 5 seconds?). I tried to use for-comprehension or flatMap and place the setCookie and complete actions inside, but the return type is unacceptable to Spray. For-comprehension returns "Unit", and flatMap returns a Future.
Since I need to set up this cookie, I need the data inside. Is Await the solution? Or is there a smatter way?
You can use the onSuccess directive:
get {
optionalCookie("commToken") { cookie =>
//....
val response = (MTurkerProgressActor ? Register).mapTo[..].map({...})
onSuccess(response) {
case (result, mTurkerResponse) =>
setCookie(HttpCookie("commToken", content = mTurkerResponse.mturker.get.commToken)) {
complete(result, mturkerResponse.mturker.get)
}
}
}
There's also onFailure and onComplete (for which you have to match on Success and Failure) See http://spray.io/documentation/1.2.1/spray-routing/future-directives/onComplete/
Also, instead of using get directly it's much more idiomatic to use map (I assume the mturker is an Option or something similar):
case (result, mTurkerResponse) =>
mTurkerResponse.mturker.map { mt =>
setCookie(HttpCookie("commToken", content = mt.commToken)) {
complete(result, mt)
}
}
You can also make a custom directive using this code -
case class ExceptionRejection(ex: Throwable) extends Rejection
protected def futureDirective[T](x: Future[T],
exceptionHandler: (Throwable) => Rejection = ExceptionRejection(_)) =
new Directive1[T] {
override def happly(f: (::[T, HNil]) => Route): Route = { ctx =>
x
.map(t => f(t :: HNil)(ctx))
.onFailure { case ex: Exception =>
ctx.reject(exceptionHandler(ex))
}
}
}
Example usage -
protected def getLogin(account: Account) = futureDirective(
logins.findById(account.id)
)
getAccount(access_token) { account =>
getLogin(account) { login =>
// ...
}
}
I need to use some Java library, which might throw some exceptions in one method and return error codes in another set of methods. So far it leads to the ugly code like
val txn = mgr.prepareTransaction()
val accessRecord = txn.readByQuery(...)
var state : Either[MyError, Result] = null //
try {
// do something here
val result = txn.runCodeWithin(new Callable[Result]() {...})
if (result == -1) {
state = Left(CanNotReadRecord)
} else {
state = Right(txn.getCachedRecord())
}
} catch {
case e: Exception => state = Left(GeneralError(e))
} finally {
state match {
case Right(_) => txn.commit();
case _ => txn.rollback();
}
}
I mostly interested in getting rid of state as var and ability to check the state in finally block. Please advice.
Scala 2.10 introduced the Try class, which is a more functional replacement to the use case of Either[Throwable, Result]. It's got all of the usual monad ops (the things that make for-comprehensions work), and some other helpful methods. (check out the docs for Try here)
Here's a possible re-implementation of your code, using Try, and replacing CanNotReadRecord with a CanNotReadRecordException. It should be functionally equivalent to your example, with the exception of that replacement.
def txResults(txn: Transaction): Try[Record] = for {
result <- Try{ txn.runCodeWithin(...) }
checked <- result match {
case -1 => Failure( new CanNotReadRecordException )
case _ => Success( txn.getCachedRecord )
}
} yield checked
txResults(txn) match {
case Success(record) => txn.commit()
case Failure(e) => txn.rollback() //and maybe handle `e`
}
The Scala ARM (Automatic Resource Management) library handles all this sort of thing elegantly and in a completely air-tight manner.
Check it out.