Making code more scala idiomatic - scala

I came across following java like code in Scala project. how to make it more Scala idiomatic with no side effects (exception handling appropriately) ?
I am thinking to use scalaz disjunction / (I know I can use Scala either too but like right biased more I guess). in a function there are a few such if checks(one above is one example) which throw one or the other type of exceptions. how to make such code more Scala idiomatic?
EDIT:
Question is not around how to convert Java null checks into Scala Idiomatic, which I am already doing. for e.g. following
hpi.fold(throw new Exception("Instance not found for id " + processInstanceId)) { h =>
val pi = new ProcessInstance(taskResponse)
Now return type of the existing function is some value say "ProcessInstance" for e.g. but in my opinion is misleading. caller would never know if this will throw an exception so my question is more around returning Either[Error,Value] from such functions. And if I have a few such exceptions being captured into a single function, how to accumulate them all and reflect into return type?

One thought might making processDefinition.getDiagramResourceName() return an Option, so you can then check whether the result is Some(x) or None.

Using scalaz and being idiomatic this is probably what I would end up with (subject to refactoring):
for {
pd <- Option(processDefinition.getDiagramResourceName()).\/>("Diagram resource could not be found")
} yield pd
So if you have null you get back Left("Diagram resource could not be found") otherwise you get Right(DiagramResourceName).

An approach based in case classes where different subclasses of names, references or labels may be defined,
trait ResourceName
case object MissingName extends ResourceName
case class DiagramResourceName(name: String) extends ResourceName
case class AnotherResourceName(ref: Int) extends ResourceName
processDefinition.getDiagramResourceName() match {
case DiagramResourceName(name) => println(s"name $name")
case MissingName => throw new ActivityException(errorMessage)
}

Related

Service class and logging design Scala with Futures

I have a service class that gets some data from a database (for context, I'm using Play! Framework). Here's an example method:
def getAccessToken(id: BSONObjectID): Future[Option[String]] = {
userDAO.find(id).map {
case Some(user) =>
user.settings flatMap (_.accessToken)
case _ => None
}
}
I'm trying to improve the error handling (new to Scala) on this thing as there are a couple things that can go wrong:
User might not be found
User might be found but accessToken might not be set (accessToken is an Option[String])
As it stands right now, I can't differentiate between the two. My natural inclination to fix this is to use \/ from Scalaz and have the return type be Future[ErrorType \/ String] and this seems like a reasonable approach. In my controller method, I can for comprehension a bunch of different service methods like this by lifting into a wrapper monad.
But I have the following questions:
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
How can I handle logging without polluting the controller class with excessive log statements? If a controller class calls a bunch of these service methods, the controller will have to handle several different ErrorTypes in the for comprehension. Assuming I'm lifting all the monads to a wrapper monad with ?|, I want to avoid this:
accessToken <- service.getAccessToken(id) ?| { error => error match { case Error1 =>
logger.error(
"Unable to find access token for user: " + id
.toString())
InternalServerError(
ApiResponse("internal_server_error",
"Unable to get token."))
case Error2 => ...
}
Thanks!
I think Future[ErrorType / String] is a bit overkill as Future[T] already can hold either an object of type T or an Exception derived one (see Future.successful(...)/ Future.failed(...))
Should my ErrorType extend Exception, or should I just use the sealed trait style and just extend from that. I've heard that it is not good practice to use exceptions in Scala, so I'm not sure what the right approach is.
I would recommend to use a class (or a set of classes, one per particular error type), say YourAppException derived from Exception, as you need to handle low level exceptions one way or another anyway.
I agree that throwing/catching exceptions is not going very well with functional code and it is better to use Try[T] or Future[T] to return errors in a more explicit way instead. On the other hand there is nothing wrong with using an Exception derived class to hold some error info. It is often useful to wrap the original non-application (say IO) exception in an application one and keep a reference to the initial one in Exception's 'cause' for troubleshooting. It gives an opportunity to provide a more context specific error message.
How can I handle logging without polluting the controller class with excessive log statements?
Consider encapsulating error messages in Exception derived case classes, representing application errors so you can access the error messsages uniformly using exception.getMessage. It is easy to add some method to YourAppException to construct ApiResponse as well.
def getAccessToken(id: BSONObjectID): Future[String] = {
userDAO.find(id).flatMap {
case Some(user) =>
val optToken = user.settings.flatMap (_.accessToken)
optToken.map(Future.successful).getOrElse(Future.failed(AccessTokenIsInvalid(user)))
case _ => Future.failed(UserNotFoundError(user))
}
}
case class AccessTokenIsInvalid(user: String)
extends YourAppException(s"Access token is invalid for user $user") {
}
accessToken <- service.getAccessToken(id) ?| { error =>
logger.error(error.getMessage)
InternalServerError(
ApiResponse("internal_server_error", error.getMessage))
}
1) Yes, you are on a right way. The problem with exceptions is that when something fails it's hard to pattern-match on it to detect a reason.
I would do it like that:
sealed trait MyError
object UserNotFound extends MyError
object AuthFailed extends MyError
type MyResult = Either[MyError, String]
2) If a program is well-typed logging is necessary in places where information is lost.
If you deal with, for example, val x = Future[Either[Error, String]], then you haven't throttled potential error yet so logging is optional.
But when you somehow try to extract Either[MyError, String] from it you lose information so you should log it.
The same happens when you extract String from Either[MyError, String].

What is the advantage of using Option.map over Option.isEmpty and Option.get?

I am a new to Scala coming from Java background, currently confused about the best practice considering Option[T].
I feel like using Option.map is just more functional and beautiful, but this is not a good argument to convince other people. Sometimes, isEmpty check feels more straight forward thus more readable. Is there any objective advantages, or is it just personal preference?
Example:
Variation 1:
someOption.map{ value =>
{
//some lines of code
}
} orElse(foo)
Variation 2:
if(someOption.isEmpty){
foo
} else{
val value = someOption.get
//some lines of code
}
I intentionally excluded the options to use fold or pattern matching. I am simply not pleased by the idea of treating Option as a collection right now, and using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO. But no matter why I dislike these options, I want to keep the scope of this question to be the above two variations as named in the title.
Is there any objective advantages, or is it just personal preference?
I think there's a thin line between objective advantages and personal preference. You cannot make one believe there is an absolute truth to either one.
The biggest advantage one gains from using the monadic nature of Scala constructs is composition. The ability to chain operations together without having to "worry" about the internal value is powerful, not only with Option[T], but also working with Future[T], Try[T], Either[A, B] and going back and forth between them (also see Monad Transformers).
Let's try and see how using predefined methods on Option[T] can help with control flow. For example, consider a case where you have an Option[Int] which you want to multiply only if it's greater than a value, otherwise return -1. In the imperative approach, we get:
val option: Option[Int] = generateOptionValue
var res: Int = if (option.isDefined) {
val value = option.get
if (value > 40) value * 2 else -1
} else -1
Using collections style method on Option, an equivalent would look like:
val result: Int = option
.filter(_ > 40)
.map(_ * 2)
.getOrElse(-1)
Let's now consider a case for composition. Let's say we have an operation which might throw an exception. Additionaly, this operation may or may not yield a value. If it returns a value, we want to query a database with that value, otherwise, return an empty string.
A look at the imperative approach with a try-catch block:
var result: String = _
try {
val maybeResult = dangerousMethod()
if (maybeResult.isDefined) {
result = queryDatabase(maybeResult.get)
} else result = ""
}
catch {
case NonFatal(e) => result = ""
}
Now let's consider using scala.util.Try along with an Option[String] and composing both together:
val result: String = Try(dangerousMethod())
.toOption
.flatten
.map(queryDatabase)
.getOrElse("")
I think this eventually boils down to which one can help you create clear control flow of your operations. Getting used to working with Option[T].map rather than Option[T].get will make your code safer.
To wrap up, I don't believe there's a single truth. I do believe that composition can lead to beautiful, readable, side effect deferring safe code and I'm all for it. I think the best way to show other people what you feel is by giving them examples as we just saw, and letting them feel for themselves the power they can leverage with these sets of tools.
using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO
If you do just want an isEmpty check, isEmpty/isDefined is perfectly fine. But in your case you also want to get the value. And using pattern matching for this is not abuse; it's precisely the basic use-case. Using get allows to very easily make errors like forgetting to check isDefined or making the wrong check:
if(someOption.isEmpty){
val value = someOption.get
//some lines of code
} else{
//some other lines
}
Hopefully testing would catch it, but there's no reason to settle for "hopefully".
Combinators (map and friends) are better than get for the same reason pattern matching is: they don't allow you to make this kind of mistake. Choosing between pattern matching and combinators is a different question. Generally combinators are preferred because they are more composable (as Yuval's answer explains). If you want to do something covered by a single combinator, I'd generally choose them; if you need a combination like map ... getOrElse, or a fold with multi-line branches, it depends on the specific case.
It seems similar to you in case of Option but just consider the case of Future. You will not be able to interact with the future's value after going out of Future monad.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Promise
import scala.util.{Success, Try}
// create a promise which we will complete after sometime
val promise = Promise[String]();
// Now lets consider the future contained in this promise
val future = promise.future;
val byGet = if (!future.value.isEmpty) {
val valTry = future.value.get
valTry match {
case Success(v) => v + " :: Added"
case _ => "DEFAULT :: Added"
}
} else "DEFAULT :: Added"
val byMap = future.map(s => s + " :: Added")
// promise was completed now
promise.complete(Try("PROMISE"))
//Now lets print both values
println(byGet)
// DEFAULT :: Added
println(byMap)
// Success(PROMISE :: Added)

Scala Constructor/Method Parameter Checking

I wanted to check some best practices of Scala programming, since I am new to Scala. I read online about how Scala doesn't typically use exceptions except for "exceptional" circumstances (which doesn't include parameter checking). Right now in my project I am using a lot of require, so I am wondering what the better way of type checking would be.
For example, if I have a class
class Foo(String bar){
require(StringUtils.isNotEmpty(bar), "bar can't be empty")
}
what are my alternatives to checking bar? Do I create a companion object like so
Object Foo {
def apply(bar: String) = Try[Foo] {
bar match = {
case null => Failure("can't be null")
//rest of checks
case _ => Success[Foo]
}
}
Or should I use Option instead?
In addition, for scala methods, how do I check the parameter of the method? If I already return an Option, do I just return an empty Option if I get a bad parameter? Wouldn't that mean I have to check for an empty Option when I use the return of the method and wouldn't throwing an exception allow for a more specific message? (e.g. runtime exception can't use nulls).
I think the Success part of your companion object would return the Foo() object as well?
Object Foo {
def apply(bar: String) = Try[Foo] {
bar match = {
case null => Failure("can't be null")
//rest of checks
case _ => Success[Foo](new Foo(bar))
}
}
To use it you might do something with the Success you get from Foo(bar):
val hehe = Foo(bar).map(foo => foo.someString()).getOrElse('failed')
The Try methods will automatically wrap exceptions generated by someString() or whatever else that you're doing inside it inside Failures. If you wanted to check the parameters of foo.someString(), you'd do something similar to your apply() method. It isn't that much different than throwing exceptions on conditions but I think it's nicer cause the "catch blocks" would be in recover() or recoverWith(). You can always exit the Try using getOrElse() if your code wasn't designed to chain Trys from top to bottom.

Scala: How to return a Some or Option

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.

Get Option value or throw an exception

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")