I have a code looking like this:
import scala.util.{Try, Success, Failure}
Try(
for (i <- 1 to 1000) {
doSomething(df(i))
}
) match {
case Success(t) => println(s"success")
case Failure(t) => println(s"failure")
}
i want to print the index of the failed input. how to print the index i in catch expression?
You can do this instead using Cats:
import scala.util.Try
import cats.implicits._
(1 to 1000).traverse(i => Try(doSomething(df(i))).toEither.left.map(ex => (ex, i))) match {
case Right(_) => println("success")
case Left((ex, i)) => println(s"failure: ${ex.getMessage} on idx: ${i}")
}
If you do not want to use Cats, you can just:
val attempts = for {
i <- Stream.range(start = 1, end = 1000) // Thanks to Bogdan for the idea of using a Stream.
} yield Try(doSomething(df(i))).toEither.left.map(ex => (ex, i))
attempts.collectFirst { case Left((ex, i)) => ex -> i } match {
case None => println("success")
case Some((ex, i)) => println(s"failure: ${ex.getMessage} on idx: ${i}")
}
You should definitely follow Luis's answer, but to address your comment, you could also catch IllegalArgumentException and re-throw it with the added index to the message, perhaps something like so:
Try(
for (i <- 1 to 1000) {
try doSomething(i) catch { case e: IllegalArgumentException => throw new IllegalArgumentException(s"Failed with index $i", e)}
}
) match {
case Success(t) => println(s"success")
case Failure(t) => println(s"failure", t)
}
However this seems hideous, and I do not advise it.
IMO the question hints that the code is lying.
you could write the code differently:
import scala.util.{Try, Success, Failure}
for (i <- 1 to 1000) {
Try(
doSomething(df(i))
) match {
case Failure(t) => println(s"failure on $i")
case _ =>
}
}
But you don't want to. Why not? Because you want to stop the iteration after the first failure. But you're using loop from 1 to 1000. You don't really intend to do the whole 1000 iterations. You're using an exception to break a for loop.
I would rewrite this code to make it clear that i don't intend to iterate the entire range explicitly.
You could, for example, use find instead of for, to find the index that causes a failure to happen. if None was found -> everything was successful.
so something similar to (untested):
(1 to 1000).indexWhere{index=>Try{doSomething(index)}.isFailure
i'm not sure if it's find or indexWhere in scala but you get the idea.
if you would like to obtain the exception as well, not just the index you could use views (https://docs.scala-lang.org/overviews/collections/views.html) to change your sequence to a lazily evaluated one, map the list to a tuple of form (index, Try) (without iterating the entire collection, due to lazyness of .view result), and then collectFirst where second element of tuple is Failure.
so something like (untested):
(1 to 1000).view.map{index => (index, doSomething(index)}.collectFirst{case (i,Failure(e)) => println(s"error was $e at index $i")}
alternatively you could write a very very small recursion to iterate the index sequence (also untested)
def findException(indexes: Seq[Int]): Option[(Int, Exception)] = indexes match {
case Nil => None
case index+:remaining =>
Try(doSomething(i)) match {
case Success(_) => findException(remaining)
case Failure(e) => Option((index,e))
}
findException(1 to 1000).map(println)
one question is how did you determine 1 to 1000?
this question would look differently if you had a collection of elements to verify, and not a range. in that case you would probably just use foldLeft.
Related
I'm using pattern matching in scala a lot. Many times I need to do some calculations in guard part and sometimes they are pretty expensive. Is there any way to bind calculated values to separate value?
//i wan't to use result of prettyExpensiveFunc in body safely
people.collect {
case ...
case Some(Right((x, y))) if prettyExpensiveFunc(x, y) > 0 => prettyExpensiveFunc(x)
}
//ideally something like that could be helpful, but it doesn't compile:
people.collect {
case ...
case Some(Right((x, y))) if {val z = prettyExpensiveFunc(x, y); y > 0} => z
}
//this sollution works but it isn't safe for some `Seq` types and is risky when more cases are used.
var cache:Int = 0
people.collect {
case ...
case Some(Right((x, y))) if {cache = prettyExpensiveFunc(x, y); cache > 0} => cache
}
Is there any better solution?
ps: Example is simplified and I don't expect anwers that shows that I don't need pattern matching here.
You can use cats.Eval to make expensive calculations lazy and memoizable, create Evals using .map and extract .value (calculated at most once - if needed) in .collect
values.map { value =>
val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
(value, expensiveCheck1, expensiveCheck2)
}.collect {
case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
...
}
I don't see a way of doing what you want without creating some implementation of lazy evaluation, and if you have to use one, you might as well use existing one instead of rolling one yourself.
EDIT. Just in case you haven't noticed - you aren't losing the ability to pattern match by using tuple here:
values.map {
// originial value -> lazily evaluated memoized expensive calculation
case a # Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
case a => a -> None
}.collect {
// match type and calculation
...
case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
...
}
Why not run the function first for every element and then work with a tuple?
Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
case ...
case (x, y) if y => y
}
I tried own matchers and effect is somehow OK, but not perfect. My matcher is untyped, and it is bit ugly to make it fully typed.
class Matcher[T,E](f:PartialFunction[T, E]) {
def unapply(z: T): Option[E] = if (f.isDefinedAt(z)) Some(f(z)) else None
}
def newMatcherAny[E](f:PartialFunction[Any, E]) = new Matcher(f)
def newMatcher[T,E](f:PartialFunction[T, E]) = new Matcher(f)
def prettyExpensiveFunc(x:Int) = {println(s"-- prettyExpensiveFunc($x)"); x%2+x*x}
val x = Seq(
Some(Right(22)),
Some(Right(10)),
Some(Left("Oh now")),
None
)
val PersonAgeRank = newMatcherAny { case Some(Right(x:Int)) => (x, prettyExpensiveFunc(x)) }
x.collect {
case PersonAgeRank(age, rank) if rank > 100 => println("age:"+age + " rank:" + rank)
}
https://scalafiddle.io/sf/hFbcAqH/3
I just started working with scala and am trying to get used to the language. I was wondering if the following is possible:
I have a list of Instruction objects that I am looping over with the foreach method. Am I able to add elements to my Instruction list while I am looping over it? Here is a code example to explain what I want:
instructions.zipWithIndex.foreach { case (value, index) =>
value match {
case WhileStmt() => {
---> Here I want to add elements to the instructions list.
}
case IfStmt() => {
...
}
_ => {
...
}
Idiomatic way would be something like this for rather complex iteration and replacement logic:
#tailrec
def idiomaticWay(list: List[Instruction],
acc: List[Instruction] = List.empty): List[Instruction] =
list match {
case WhileStmt() :: tail =>
// add element to head of acc
idiomaticWay(tail, CherryOnTop :: acc)
case IfStmt() :: tail =>
// add nothing here
idiomaticWay(tail, list.head :: acc)
case Nil => acc
}
val updatedList = idiomaticWay(List(WhileStmt(), IfStmt()))
println(updatedList) // List(IfStmt(), CherryOnTop)
This solution works with immutable list, returns immutable list which has different values in it according to your logic.
If you want to ultimately hack around (add, remove, etc) you could use Java ListIterator class that would allow you to do all operations mentioned above:
def hackWay(list: util.List[Instruction]): Unit = {
val iterator = list.listIterator()
while(iterator.hasNext) {
iterator.next() match {
case WhileStmt() =>
iterator.set(CherryOnTop)
case IfStmt() => // do nothing here
}
}
}
import collection.JavaConverters._
val instructions = new util.ArrayList[Instruction](List(WhileStmt(), IfStmt()).asJava)
hackWay(instructions)
println(instructions.asScala) // Buffer(CherryOnTop, IfStmt())
However in the second case you do not need scala :( So my advise would be to stick to immutable data structures in scala.
What is the best Scala idiomatic approach to verify that filter returns only one results (or specific amount in that matter), and if the amount correct, to continue with it?
For example:
val myFilteredListWithDesiredOneItem = unfilteredList
.filter(x => x.getId.equals(something))
.VERIFY AMOUNT
.toList
Consider this for a list of type T,
val myFilteredListWithDesiredOneItem = {
val xs = unfilteredList.filter(x => x.getId.equals(something))
if (xs.size == n) xs.toList
else List.empty[T]
}
Not a oneliner, the code remains simple none the less.
Try a match with guards, perhaps?
list.filter(...) match {
case Nil => // empty
case a if (a.size == 5) => // five items
case b#(List(item1, item2) => // two (explicit) items
case _ => // default
}
Something like this perhaps:
Option(list.filter(filterFunc))
.filter(_.size == n)
.getOrElse(throw new Exception("wrong size!"))
effective scala style states the following:
this is both succinct and correct, but nearly every reader will have a
difficult time recovering the original intent of the author. A
strategy that often serves to clarify is to name intermediate results
and parameters:
val votesByLang = votes groupBy { case (lang, _) => lang }
val sumByLang = votesByLang map { case (lang, counts) =>
val countsOnly = counts map { case (_, count) => count }
(lang, countsOnly.sum)
}
val orderedVotes = sumByLang.toSeq
.sortBy { case (_, count) => count }
.reverse
what I fail to understand is in this style if i have errors while evaluating the value for votesByLang, sumByLang, ... how can I have a single recover at the end after all if i just had .map.map ... I could have a single recover at the end. So is it possible to have a single recover also with this style? (and not only possible but with good style...)
Or in other words what is the succinct and correct error handling in this succinct and correct functional pipelining code?
you see with the non-concise version i'm able to code this:
object MyRealMainObj extends App {
println(
Try(1)
.map(doOne)
.map(doTwo)
.recover { // non succinct version can catch any prior error how to achieve the same in succinct version
case e: Throwable => println("recovering from: " + e.getMessage)
}
)
def doOne(i: Int): Int = { i + 1; throw new RuntimeException("failed in one") }
def doTwo(i: Int): Int = { i + 2; throw new RuntimeException("failed in two") }
}
a single recover will catch any previous error in the .map but with the concise-succinct how can I achieve the same in concise and succinct way?
It sound like you expect some sort of scope to be magically created by .recover. This is not the case. With some minor simplifications, Try(expr) is
try {
val result = expr
Success(result)
catch {
e => Failure(e)
}
tryResult.map(f) is :
tryResult match {
case Success(x) => Try(f(x))
case f: Failure => f
}
tryResult.recover(f) is
tryResult match {
case Failure(e) if f.isDefinedAt(e) => Try(f(e))
case other => other
}
There is no special magic. At every stage, you have values, not code in the scope of some try/catch. Putting those values in val will not change a thing. If you "debug by hand", you will notice that you get a Success object, then at some point, one of your map may fail and return a Failure, the following ones will keep being failures, and then when you pass the last one to recover, it may go back to Success. Settings vals in between cannot make any difference.
I have some code for validating ip addresses that looks like the following:
sealed abstract class Result
case object Valid extends Result
case class Malformatted(val invalid: Iterable[IpConfig]) extends Result
case class Duplicates(val dups: Iterable[Inet4Address]) extends Result
case class Unavailable(val taken: Iterable[Inet4Address]) extends Result
def result(ipConfigs: Iterable[IpConfig]): Result = {
val invalidIpConfigs: Iterable[IpConfig] =
ipConfigs.filterNot(ipConfig => {
(isValidIpv4(ipConfig.address)
&& isValidIpv4(ipConfig.gateway))
})
if (!invalidIpConfigs.isEmpty) {
Malformatted(invalidIpConfigs)
} else {
val ipv4it: Iterable[Inet4Address] = ipConfigs.map { ipConfig =>
InetAddress.getByName(ipConfig.address).asInstanceOf[Inet4Address]
}
val dups = ipv4it.groupBy(identity).filter(_._2.size != 1).keys
if (!dups.isEmpty) {
Duplicates(dups)
} else {
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
val taken: Iterable[Inet4Address] = ipAvailability.filter(!_._2).keys
if (!taken.isEmpty) {
Unavailable(taken)
} else {
Valid
}
}
}
}
I don't like the nested ifs because it makes the code less readable. Is there a nice way to linearize this code? In java, I might use return statements, but this is discouraged in scala.
I personally advocate using a match everywhere you can, as it in my opinion usually makes code very readable
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil =>
val ipv4it = ipConfigs.map { ipc =>
InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address]
}
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil =>
val taken = ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys
if (taken.nonEmpty) Unavailable(taken) else Valid
case dups => Duplicates(dups)
}
case invalid => Malformatted(invalid)
}
Note that I've chosen to match on the else part first, since you generally go from specific to generic in matches, since Nil is a subclass of Iterable I put that as the first case, eliminating the need for an i if i.nonEmpty in the other case, since it would be a given if it didn't match Nil
Also a thing to note here, all your vals don't need the type explicitly defined, it significantly declutters the code if you write something like
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
as simply
val ipAvailability = ipv4it.map(ip => (ip, isIpAvailable(ip)))
I've also taken the liberty of removing many one-off variables I didn't find remotely necessary, as all they did was add more lines to the code
A thing to note here about using match over nested ifs, is that is that it's easier to add a new case than it is to add a new else if 99% of the time, thereby making it more modular, and modularity is always a good thing.
Alternatively, as suggested by Nathaniel Ford, you can break it up into several smaller methods, in which case the above code would look like so:
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil => wellFormatted(ipConfigs)
case i => Malformatted(i)
}
def wellFormatted(ipConfigs: Iterable[IpConfig]): Result = {
val ipv4it = ipConfigs.map(ipc => InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address])
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil => noDuplicates(ipv4it)
case dups => Duplicates(dups)
}
}
def noDuplicates(ipv4it: Iterable[IpConfig]): Result =
ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys match {
case Nil => Valid
case taken => Unavailable(taken)
}
This has the benefit of splitting it up into smaller more manageable chunks, while keeping to the FP ideal of having functions that only do one thing, but do that one thing well, rather than having god-methods that do everything.
Which style you prefer, of course is up to you.
This has some time now but I will add my 2 cents. The proper way to handle this is with Either. You can create a method like:
def checkErrors[T](errorList: Iterable[T], onError: Result) : Either[Result, Unit] = if(errorList.isEmpty) Right() else Left(onError)
so you can use for comprehension syntax
val invalidIpConfigs = getFormatErrors(ipConfigs)
val result = for {
_ <- checkErrors(invalidIpConfigs, Malformatted(invalidIpConfigs))
dups = getDuplicates(ipConfigs)
_ <- checkErrors(dups, Duplicates(dups))
taken = getAvailability(ipConfigs)
_ <- checkErrors(taken, Unavailable(taken))
} yield Valid
If you don't want to return an Either use
result.fold(l => l, r => r)
In case of the check methods uses Futures (could be the case for getAvailability, for example), you can use cats library to be able of use it in a clean way: https://typelevel.org/cats/datatypes/eithert.html
I think it's pretty readable and I wouldn't try to improve it from there, except that !isEmpty equals to nonEmpty.