I have a bit of code that I am checking with Scala Scapegoat. I am not sure how to refactor this code the way it wants.
def strToDouble(valueParam: Option[String]): Option[java.lang.Double] = {
valueParam.map(value => {
Try {
Double.box(value.toDouble)
}.recoverWith({
case e: NumberFormatException => {
val logger = LoggerFactory.getLogger(getClass.getName)
logger.warn("error parsing string to double", e)
return None
}
}).getOrElse(null)
})
}
Scapegoat is complaining about my use of return and the getOrElse(null). Unfortunately in this situation I can't figure out how to do what I want:
convert the string to double, returning Option[Double]
log an error if there is a parsing error
return None in the case of parsing error
any ideas?
In general in Scala, you never need to use return, and it has some surprising semantics so it's generally advised to never use return.
Instead of return, the result of a block expression (such as the body of a function) is the result of the last expression evaluated in the block.
I would write your code along these lines
valueParam.flatMap { value =>
val attempt =
Try {
Double.box(value.toDouble)
}
attempt.recoverWith {
case e: NumberFormatException =>
val logger = LoggerFactory.getLogger(getClass.getName)
logger.warn("error parsing string to double", e)
attempt
}.toOption
}
The first key difference is that since we're transforming an Option into another Option, and might sometimes turn a Some into a None (e.g. Some("hello")), flatMap is called for.
Saving the Try[Double] in a local val enables us to get around there not being a foreach equivalent on a failed Try, thus the recoverWith which results in the same Try after side-effecting.
At the end, we convert the Try into an Option with toOption.
null is generally never used in Scala, with Option preferred (and an Option which could be null is especially verboten, as it's virtually guaranteed to blow up). If you have an Option[java.lang.Double] and need a possibly null java.lang.Double in order to work with a Java API, the orNull method on an Option is probably the most idiomatic thing to use.
I'm fairly sure that scala.Double is, on the JVM, a compiler-synthesized alias for java.lang.Double, so Double.box might not be needed.
Everything that #Levi said. I just have a preference for fold() in place of recooverWith().
import scala.util.Try
def strToDouble(valueParam: Option[String]): Option[Double] =
valueParam.flatMap { value =>
Try(value.toDouble).fold({
case e:NumberFormatException =>
LoggerFactory.getLogger(getClass.getName)
.warn("error parsing string to double", e)
None
}, Some(_))
}
Related
I have the below block of code. My intent is to do some processing with the method params and return Future[Int] or fail the Future. I want to fail the Future if my argument to method inside the Future is of type None. I have the below code. I wonder if there is a much more concise and functional way to achieve the same.
def testoption(myFutOptInt: Future[Option[Int]]) = {
myFutOptInt.map { myOptInt =>
myOptInt match {
case None => throw new BadRequestException("Oh no.....") //Future.failed(BadRequestException(""))
case Some(myInt) => myInt + 45
}
} recoverWith {
case e:Exception => Future.failed(e)
}
}
I am not liking the part that I have to do a match, wondering if there is a way to do a map or something better and still achieve it. If I do getOrElse I guess I won't be able to write the business logic if the value is not None? So getOrElse is not possible either I think?
The other thing I do not like about this code is that I am throwing an exception and then I have to do recoverWith to fail the Future.
I can enhance the above code how?
If you need specifically BadRequestException, this is enough:
def testoption(myFutOptInt: Future[Option[Int]]) =
myFutOptInt.map {
case None => throw new BadRequestException("Oh no.....")
case Some(myInt) => myInt + 45
}
And if you don't care about particular error type, you can cut it even more:
def testoption(myFutOptInt: Future[Option[Int]]) = myFutOptInt.map(_.get + 45)
This will give you java.util.NoSuchElementException: None.get if there's no value
recoverWith is absolutely redundant b/c if an exception is thrown inside a map, whole operation results in a failed Future. This is true for most, if not all, Future methods.
For match, you can avoid it using opt.fold(throw ...)(...) or .map(...).getOrElse(throw ...), but I'd argue those options are less readable. I suggest just using pattern-matching function definition to reduce extra code
Suppose I have many akka services which all return a case class of type AbcDto wrapped in a Try.
So I call all these services using map and get back a List[Future[Any]].
Now I use Future.sequence to convert this to Future[List[Any]].
How do I unwrap my final list of results? I want to process them only when all of them are a Success and even if one fails I want to throw an error.
I tried mapping Future[List[Any]] as:
val a: List[Future[Any]]
a.map {
case r: List[Success[AbcDto]] => println("hello")
}
But this gives error:
case r: List[Try[AbcDto]]. At this point its giving error: non-variable type argument scala.util.Try[AbcDto] in type pattern List[scala.util.Try[AbcDto]] (the underlying of List[scala.util.Try[AbcDto]])
since all akka services return AbcDtowrapped in a Try the proper type of val a should be List[Future[Try[AbcDto]]]. Now the desired result can be achieved by a combination of Future.sequence and flatMap operation to check for any Failures in the service as shown below.
val a: List[Future[Try[AbcDto]]] = ...
val result: Future[List[AbcDto]] = Future.sequence(a) flatMap {
case r: List[Try[AbcDto]] #unchecked if r.find(!_.isSuccess).isDefined => Future.failed(new RuntimeException("not all results are successful"))
case r => Future.successful(r.collect({ case Success(x) => x}))
}
Future[A] and Try[A] in the actor context are so similar that I see no point to return Try[A] from those actors. You just return A in case of success, which will be Future[A] on asking side, a List of which you can sequence and get Future[List[A]], which, in case of a single failure, will contain the first encountered exception. It seems to be exactly what you're asking for.
To communicate failure from an actor to the asker, you should send akka.actor.Status.Failure with the relevant instance of Throwable.
P.S. regarding comment that using try-catch is non-idiomatic Scala. It actually is. Here's how Try creation is implemented:
object Try {
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
}
As you can see, it uses try-catch inside. If Scala standard library authors are fine with that, so should be you. :)
If I understand you correctly (the types in your question are a bit confusing),
You start with a val responseFutures: List[Future[Any]] and after conversion you have a val responsesFuture: Future[List[Any]]. rogue-ones answer is correct, but it could use some clarification:
Your compiler error is caused by the fact that Success is not a class, but an extractor object with unapply for Try. Therefore you cannot use in in type extraction this way.
So something like case r: List[Try[AbcDto]] if r.forall(_.isSuccess) => println("hello") should compile. However, as AbcDto is erased, you will get a compiler warning about erasure. Thus the #unchecked.
UPDATE
Type erasure means, the compiler cannot check type argument type in pattern matches at compile time. In your case, all the compile knows of your input type is Future[List[Try[Any]]].
So
future.map {
case _: List[Try[AbcDto]] => ???
}
will cause a compiler warning because the compiler only sees.
future.map {
case _: List[Try[_]] => ???
}
The #unchecked annotation just suppresses the corresponding compiler warning.
In the end with the pattern match above you just cast whatever is coming in to Try[AbcDto] without any compile time type safety.
I'm new to Scala, being slightly confused at the various ways to handle exceptions and looking for best-practice advice on the topic. I'm writing a simple method to retrieve a Customer using an existing blocking SDK. The possible outcomes are:
Customer is found
Customer is not found (comes back as a NotFoundException from the SDK)
Error while talking to remote server (SDK throws some other exception)
So I want my method to have a return type Future[Option[Customer]], and return for each case above:
Successful Future: Some(customer)
Successful Future: None
Failed Future
Here is what I wrote using try/catch:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
try {
Some(gateway.find(userId))
} catch {
case _: NotFoundException => None
}
}
This works fine and seems clean to me, but doesn't seem to be really the "Scala way" to do it - I've been told to avoid using try/catch. So I've been looking for a way to rewrite it using a Try instead.
Here are 2 variants that (I think) behave exactly the same, using a Try.
Variant A:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}.get
}
Variant B:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}
} flatMap {
case Success(s) => Future.successful(s)
case Failure(f) => Future.failed(f)
}
I'm not a huge fan of A (even though it's more concise than B) since the .get seems a bit treacherous. B is definitely the most explicit but mapping the Try cases to corresponding Future outcomes seems boring.
How would an experienced Scala programmer write this?
I think your initial version using try/catch is perfectly fine, because it's a wrapper around an existing SDK.
Alternatively, you can use the recover method on Future:
def findCustomer(userId: Long): Future[Option[Customer]] =
Future(Option(gateway.find(userId))).recover {
case e: NotFoundException => None
}
One option is to avoid chaining Try and Future. In a sense, a future is an asynchronous Try.
You could use Future[Customer] directly and consider NotFoundException as something to recover from rather than a None value. Normally, you would chain operation on the future itself, with no need to deal with the failure cases (by mapping it, etc). It all depends on how you are going to use it (how your logic branches when the future is completed). In other words, maybe it seems convoluted to you because it is, and you are forcing it to be by forcing the Future[Option[Customer]] return type.
The ability to do chain multiple operations and carry on with computing if and only if all if going all right is the nice Scala feature here (especially on for comprehensions, etc).
You might be looking for:
Future.fromTry(myTry)
So for your example you might do:
Future.fromTry {
Try(Some(gateway.find(userId))).recover {
case _: NotFoundException => None
}
}
To only catch the NotFoundException, as in your solution. The only problem here is that the method won't be executed asynchronously. If that is necessary, consider using Future.recover, as suggested by Ionut.
Another idiomatic option worth mentioning here is to use Either[F, S], where S is the type of the successful return, and F can hold the errors (which you might want to propagate). So you could use Either[ Exception, Option[String]] or Either[String, Option[String]] where the first String is an error message.
If you're ready to adopt some scalaz. disjunction from scalaz is very useful and natural in handling erronous scenarios. It's like scala Either but scalaz disjunction \/ is right biased. you'll have success value on the right and exception on left. wrapping your code block with \/.fromTryCatch returns exception on the left side of disjunction. right will always have success value. mapping over disjunction is easiser than Scala Either since disjunction is right biased and easily gives you value from right.
import scalaz.\/
private def findCustomer(userId: Long): Future[\/[Throwable,Option[Customer]] ]= future {
\/.fromTryCatch {
Some(gateway.find(userId))
}
}
I have the following piece of code that I am trying to enhance:
I am using the java.nio.file package to represent a directory or a file as a Path.
So here goes:
import java.nio.file.{Paths,DirectoryStream,Files,
Path,DirectoryIteratorException}
val path: Path = Paths.get(directoryPath)
var directoryStream: Option[DirectoryStream[Path]] = None
// so far so good
try {
directoryStream = Some(Files.newDirectoryStream(pathO))
// this is where i get into trouble
def getMeDirStream: DirectoryStream[Path] =
if (!directoryStream.isEmpty && directoryStream.isDefined)
getMeDirStream.get
else
None
// invoke the iterator() method of dstream here
}
The above piece of code will not compile because I do not know what to return in the else, and right now, for the life of me, I can only come up with None, which the compiler simply does not like and I would like to learn what should be its replacement.
I want this example to be a learning lesson of Option and Some for me.
Okay, this is where I choke. I would like to check if the directoryStream is not empty and is defined, and then if this is the case, I would like to invoke getMeDirStream.get to invoke the iterator() method on it.
The API for Option tells me that invoking the get() method could result in a java.util.NoSuchElementException if the option is empty.
If the directoryStream is empty I want to return something and not None, because IntelliJ is telling me that "Expression of type None.type doesn't conform to expected type DirectoryStream[Path]".
Now, I am being all naive about this.
I would like to know the following:
What should I return in the else other than None?
Should I wrap the getMeDirStream.get in a try-catch with a java.util.NoSuchElementException, even though I am checking if the directoryStream is empty or not.?
What is the purpose of a try-catch in the getMeDirStream.get, if there is indeed such a need?
How can I clean up the above piece of code to incorporate correct checks for being isDefined and for catching appropriate exceptions?
Once I know what to return in the else (and after putting in the appropriate try-catch block if necessary), I would like to invoke the iterator() method on getMeDirStream to do some downstream operations.
Some and None are subtypes of Option, but to be more correct, they are actually two different cases of Option or data constructors. In other words, even though Scala allows you to directly invoke a Some or a None you should still regard their type to be Option. The more important thing to take from this is that you should never under any circumstance invoke Option#get as it is unsafe.
The intention of Option is to indicate the possibility that a value does not exist. If you care about the errors, then you should probably look at using Either instead (or Scalaz's Either called \/).
You can keep the computation within the Option context and then only extract the value later, or provide a default.
def fromTryCatch[A](a: => A): Either[Throwable, A] = try { Right(a) } catch { case e: Throwable => Left(e) }
val getMeDirStream: Option[java.util.Iterator[Path]] =
for {
path <- fromTryCatch(Paths.get(directoryPath)).toOption
directoryStream <- fromTryCatch(Files.newDirectoryStream(pathO)).toOption
} yield directoryStream.iterator()
Later, or right after, you can get the iterator, or provide a default value:
val iterator = getMeDirStream.getOrElse(java.util.Collections.emptyIterator[Path])
Your specific questions are difficult to address because it's unclear exactly what you're trying to achieve. In particular, when you ask what the purpose of the try block is... Well, you wrote it, so only you can answer that.
In general, you never call get on an Option. You either use pattern matching:
option match {
case Some(value) => /* ... */
case None => /* ... */
}
or you use methods like map, flatMap, and foreach (or the equivalent comprehension syntax that gpampara's code uses).
My revision of gpampara's answer:
import scala.collection.convert.wrapAll._
import scala.util.Try
import java.nio.file.{Paths, Files, Path}
val getMeDirStream: Option[Iterator[Path]] =
for {
path <- Try(Paths.get("")).toOption
directoryStream <- Try(Files.newDirectoryStream(path)).toOption
} yield directoryStream.iterator
Changes:
Using Try(...).toOption instead of Either
Using implicits in scala.collection.convert to return the result as a Scala Iterator.
Try is similar to Option. Instead of Some and None, it has Success and Failure subtypes, and the failure case includes a Throwable, whereas None is just a singleton with no additional information.
Given an Option, what is the idiomatic way to get its value or throw an exception trying?
def foo() : String = {
val x : Option[String] = ...
x.getOrException()
}
A throw "statement" is really an expression in Scala, and it has type Nothing, which is a subtype of every other type. This means you can just use plain old getOrElse:
def myGet[A](oa: Option[A]) = oa.getOrElse(throw new RuntimeException("Can't."))
You really, really shouldn't be doing this, though.
(EDIT: this is not the best or most idiomatic way to do it. I wrote it when I was not familiar with Scala. I leave it here for an example of how not to do it. Nowadays I would do as #TravisBrown)
I think it really boils down to two things:
how sure are you that the value is there?
how do you want to react if it isn't?
If at that point in your code you expect the value to be there, and in the remote case that it isn't you want your program to fail fast, then I would only do a normal get and let Scala throw a NoSuchElementException if there was no value:
def foo() : String = {
val x : Option[String] = ...
x.get
}
If you want to handle the case differently (throw your own exception) I think a more elegant way would look like this:
def foo(): String = {
val x: Option[String] = None
x match {
case Some(value) => value
case None => throw new MyRuntimeException("blah")
}
}
And of course if you want to supply your own alternative value for the case that the Option is None you would just use getOrElse:
def foo(): String = {
val x: Option[String] = None
x.getOrElse("my alternative value")
}
I hope this will help you to understand how to represent errors (and generally effects) using types.
Error handling strategies in functional Scala
Use Option to return optional values. For example - fail to find entity in storage.
Use Option(possiblyNull) to avoid instances of Some(null).
Use Either[Error, T] to report expected failure. For example - email format is wrong, cannot parse a string to a number, etc.
Model your errors as ADTs (simply speaking kind of type hierarchies) to use it, for example, on the Left of the Either to represent more complex error scenarios.
Throw Exception only to signal unexpected and not-recoverable failures. Like missing config file.
Use Either.catchOnly or Try or Cats.IO (advanced) rather than a catch block for handling unexpected failures. Hint: You can still use ADT but extend them from throwables. More about Either vs Try.
Use Validated data-type from Cats lib to accumulate errors rather than fail-fast (Either), but prefer Either's on module-level to simplify the composition of the program (to have the same types). For example - form data validation, parsing errors accumulation.
Use mentioned types and don't optimize program preemptively - since most probably, bottle-necks would be in business logic, not in effect types.
Such an approach will simplify maintenance and updates of your code since you can reason about it without going to implementation specifics (aka local-reasoning). Also - reduce bugs - you cannot miss an error in the type. And compose the program easier (with help of map, flatMap and other combinators) - since it's simpler on type level, rather than with non-local exceptions and side-effects.
More about learning functional Scala.
But be aware that sometimes with this approach types could stack up and it could become harder to compose things. Given, for example: x: Future[Either[Error, Option[T]]] What you can do:
Use map and flatMap in combination with pattern-matching to compose different values of such types, for example:
x.faltMap { case Right(Some(v)) => anotherFuture(v); case Left(er) => ... }
If it doesn't help you can try to use MonadTransformers (don't be scared of the name, it's just wrappers around the effect types like Either and Future)
Also, an option is to simplify your errors ADT by extending them from the Throwable to unify it with Future, then it'll be Future[Option[T]]
And finally, in your case one option will be:
def foo() : Either[Error, String] = {
val x : Option[String] = ...
x match {
case Some(v) => Right(v)
case None => Left(Error(reason))
}
}
Just use the .get method.
def get[T](o:Option[T]) = o.get
It will throw a NoSuchElementException if o is an instance of None.
Basically, I would work with options like this:
def addPrint(oi:Option[Int]) = oi.map(_+1).foreach(println)
addPrint(Some(41))
addPrint(Some(1336))
addPrint(None)
to avoid your specific question.
Scala now support this operation on maps using getOrElse() method, see documentation here
As pointed out already, throwing an exception in Scala is an expression as well.
So you can do the following:
myMap.getOrElse(myKey, throw new MyCustomException("Custom Message HERE")