Scala update object fields incrementally - scala

I need to build records with multiple fields.
The record definition is like:
class Record(
f1: Int,
f2: String,
...
err: String
)
The logic is like:
record.f1 = get_f1()
record.f2 = get_f2()
...
The calls to get_f1 etc may throw exceptions. When this happen, we set record.err to the exception message.
Right now, my hacky solution is to use a mutable Record instance and patch the fields incrementally. When exception happens, I'll catch it from an outer function and set the err field.
The question is how can I implement this in a more functional way?
------ edit -----
We need the err field to output the first exception
When exception happens, we still want to output the fields already populated

The question is how can I implement this in a more functional way?
By properly modeling this in a functional style.
First, let's remove the err field from the case class, and rather use Either
Second, let's properly handle the nulls using Option
Finally, let's use a functional library like cats.
The end result would be something like this:
import cats.data.EitherNec
import cats.syntax.all._
type Error = String // You may use a better data type.
final case class Record(
f1: Int,
f2: String,
f3: Boolean
)
object Record {
def fromRawData(f1: Option[Int], f2: Option[String], f3: Option[Boolean]): EitherNec[Error, Record] =
(
f1.toRightNec(left = "F1 was empty"),
f2.toRightNec(left = "F2 was empty"),
f3.toRightNec(left = "F3 was empty")
).parMapN(Record.apply)
}
The EitherNec[E, A] is just an alias for Either[NonEmptyChain[E], A]
Meaning that if it is a Left it will hold all the errors;
it also implies that there must be at least one error.
Feel free to ask any follow-up questions you may have.
If you don't want to use cats you can replace the parMapN with a for; but this will stop at the first failure.
You can see the code running here.

This is a (mostly) functional way of doing this:
import scala.util.{Try, Success, Failure}
Try {
Record(getf1(), getf2(), "")
} match {
case Success(r) => r
case Failure(e) => Record(0, "", e.getMessage)
}
If the code inside the Try runs OK then it will return Success and the match will extract the value and return it.
If the code throws an exception then it will be caught by the Try and it will return Failure. The match will catch the error code and then create a value of Return with err set to the error message from the exception.
As others have mentioned, the Either type is a better way of handling the error case as it removes the error information from the Record class itself:
Try {
Record(getf1(), getf2())
}.toEither
The result will be Right(<record>) on success or Left(<exception>) on error. You can use match to determine which answer was given.
For the modified question you need to use a nested chain of Try calls, with one level of nesting for each field in the record.
Try(getf1()) match {
case Failure(e) => Record(0, "", e.getMessage)
case Success(f1) =>
Try(getf2()) match {
case Failure(e) => Record(f1, "", e.getMessage)
case Success(f2) => Record(f1, f2, "")
}
}
This rather tortuous code is the consequence of the hybrid error handling approach in the question. A more standard design would do error handling for the whole record (as in the examples above) or for each individual field (by making each field an Option or Either value).

Related

Best Practices and Approaches while implementing pure functional Scala code which is dependent on impure code/libraries

I am currently Implementing business logic code which is dependent on the custom scala library which has a lot of impure functions and we have a lot of code with is dependent on this library and cannot refactor as it will affect others. So I am trying to write my scala code as pure as possible and need suggestions for few use cases.
I have an LDAP utility library that does the following
Authenticate based on username and password and returns Boolean, However, if there is a Connection exception or user not found it directly throws an exception.
Reading and updating data based on UUID and parameters like first name and last name does pretty much the same thing
My approach for the authentication use case is below
def authenticateToUpdate(userName:String,password:String):Option[Boolean] =
Some(ldapService.authenticate(username,password))
// or using either type to get the message as well
def authenticateToUpdate(userName:String,password:String):Either[String,Boolean]=
(ldapService.authenticate(username,password)) match {
case true => Right(true)
case false => Left("Validation failed, Invalid Password")
case exception: Exception => Left(exception.toString)
}
//##for Some type
authenticateToUpdate(userName,password).fold(InvalidPassword)(updateOrder(orderId,userName))
//##for Either type
// Looking into how to implement
So I want to write my code as functional and close to pure function as possible need help and suggestions on how can I approach such scenario to write functional scala code.
As Tim says, when handling errors in Scala the easiest thing to do is to wrap the exception-throwing code in a Try block. For example:
import scala.util.{Try, Success, Failure}
Try {
connector.makeCall()
} match {
case Success(value) if value => Right("yay")
case Success(value) => Left("☹️")
case Failure(ex) => Left("An exception was thrown")
}
This will return a Right if the connector.makeCall() line returns true or a Left if that line returns false or an exception.
It's a bit of a contrived example but here's one way you'd use this - https://scastie.scala-lang.org/irmbBQ9ISeqgitRubC8q5Q
Actually, the provided piece of code cannot be pure because the result of
authenticateToUpdate depends not only on its arguments (username, password) but also depends on the ldapService service.
Having said that I'd suggest the following definition for authenticateToUpdate:
def authenticateToUpdate(userName:String, password:String)(ldapService: (String, String) => Boolean): Either[String, String] = {
Try(ldapService(userName, password)) match {
case Success(value) if value => Right("OK")
case Success(_) => Right("Failed to authenticate")
caseFailure(ex) => Left(s"Something wrong: ${ex}")
}
}
authenticateToUpdate("user", "password"){ case (user, password) =>
ldapService.authenticate(username,password)
}
In the provided example we just wrap an impure function with a pure one.

Difference between Future[Any] and Future[_]

Okay, I guess question is already complete in the title.
Nothing big, but I am just wondering. I have a method which returns either a correct value or an error code enum item. For example something like this:
def doMyStuff(): Future[_] = {
val result = db.queryMyData().map {
case some(data) =>
val modifiedData = data.doStuff()
modifiedData
case None =>
Errors.THIS_IS_FALSE
}
result
}
Where db.queryMyData() returns a Future, and data.doStuff() just modifies the data.
Now I have intuitively written Future[_], cause the return value is flexible. But when looking in other libraries I've seen Future[Any] used. Which seems to be logic too, when you use a match-case on the return of the function to check which data it is.
The code which uses that is for example something like this:
doMyStuff().map {
case data: MyDataType => // Blah blah
case Errors.Value => // error handling
}
So, my questions is: What's the difference between the use of Any or _ here, and why should I use the correct one?
It is a matter of semantics:
The Existential TypeT[_] means there is a class/type at the position of _ for which I do not care at all but it must be there.
T[Any] means there has to be a subclass Any present.
The difference comes into play when you want to serialize the underlying class.
If you just use _ without any typebounds you will not be able to use some of the many Scala JSON libraries.

Scala: line by line check for None, or check for exceptions at the end?

I have a case class Application that has some input ports, and each port has a name. Then I have another case class that assigns values to the ports of an application.
case class Port (id: ObjectId, name: String, PortType: String)
case class Application (id: ObjectId, ports: List[Port])
case class AppRun (appId: ObjectId, assignments: List[Assignment])
case class Assignment (portName: String, value: String, valueType: String)
I have the applications and their port information in a database, and I get as input an AppRun. I need to make a list of PortValue type (below) showing the value assigned to each port (and the matching is done on port names):
case class PortValue (portId: ObjectId, value: String)
There are a few things that may fail during this matching: application id is invalid, ports do not match, etc. It feels natural to me to write the straightforward algorithm and then catch all exceptions, but that seems Java-ish. On the other hand, I cannot think of a neat way of dealing with Options , checking them one by one, which will obfuscate the code.
The question is how would you solve this Scala way?
EDIT: I need to send a proper message back when such a mismatch happens, like "application not found", etc.
A way to deal with checking Options one by one is to use a for-comprehension. And if you want to keep track of errors you can quite often replace Option with some class that does error-tracking. The common possibilities include:
scala.util.Try[T]. Try is either a Success(result), or a Failure(error: Throwable). It is a built-in class in Scala, and it is simple to combine it with or replace it by scala.concurrent.Future if the need arises.
scala.util.Either[E, T]. Creating a Throwable for every error may not be very efficient because of the need to build the stacktrace. So Either is useful if the error can be a simple String or some application-specific class without the stacktrace. The convention is to have a Right(result) or a Left(error). The downsides are that it's not semantic to have 'right' mean 'success' and 'left' mean 'error', and when you use it in a for-comprehension or call e.g. map method on it, you have to specify whether you want either.right or either.left.
scalaz.\/[E, T] This is the same as Either, but the default for map and for-comprehension is its right side (\/-). Also scalaz provides very useful functions sequence and traverse (see the code below).
scalaz.Validation[Errors, T] or scalaz.ValidationNel[E, T]. Adds a very useful functionality of collecting all the errors, but has slight problems when used in for-comprehensions.
Here is some sample code for your problem, using Try:
import scala.util.{Try, Success, Failure}
def getApplication(appId: ObjectId): Option[Application] = ???
/** Convert Option to Try, using a given failure in case of None */
def toTry[T](option: Option[T])(failure: => Throwable): Try[T] =
option.fold[Try[T]](Failure(failure))(Success(_))
/** Convert a List of Try to a Try of List.
* If all tries in the List are Success, the result is Success.
* Otherwise the result is the first Failure from the list */
def sequence[T](tries: List[Try[T]]): Try[List[T]] =
tries.find(_.isFailure) match {
case Some(Failure(error)) => Failure(error)
case _ => Success(tries.map(_.get))
}
def traverse[T, R](list: List[T])(f: T => Try[R]): Try[List[R]] =
sequence(list map f)
def portValues(task: AppRun): Try[List[PortValue]] = for {
app <- toTry(getApplication(task.appId))(
new RuntimeException("application not found"))
portByName = app.ports.map(p => p.name -> p).toMap
ports <- traverse(task.assignments) { assignment =>
val tryPort = toTry(portByName.get(assignment.portName))(
new RuntimeException(s"no port named ${assignment.portName}"))
tryPort.map(port => PortValue(port.id, assignment.value))
}
} yield ports
Some considerations:
Provided implementations of toTry, sequence and traverse are just a sample. For one, I'd define them in implicit classes to be able to call them like normal methods (e.g. option.toTry(error), or list.traverse(f)).
traverse can be implemented more effectively (stop after the first error is found).
this sequence implementation would return only the first erroneous port.
I prefer API like def getApplication(id: ObjectId): Try[Application] instead of an Option result, because you usually want to have the same error in every part of the code that calls it, and it may give different errors as well (e.g., id not found or network error). If you have def getApplication(id: ObjectId): Application that may throw an error you can simply wrap it in Try: for { app <- Try(getApplication(id)) ...

Fusing execution flow and exception flow in Scala

I am using the following to wrap a Boolean function and return its success status:
def wrapper(wrapped: => Boolean) : Boolean = { // this form of prototype takes a function by name
try {
return wrapped
} catch {
case anyException : Throwable =>
log(anyException.toString)
return false }
}
The rationale being that the wrapper function should return an overall binary status, regardless of whether the wrapped function failed to capture its own unexpected exceptions and do the same. So the wrapper conveys success and failure via its Boolean return value. It can also be an Option for function result data, rather than a Boolean.
How would you accomplish this in other, even better ways, in Scala?
I note that one rationale (of few others) for this code, admittedly has been that try catch blocks are cumbersome in flow control blocks. Another has been that I tend to use this pattern a lot in a certain area of my project.
You can use Try. Although it will catch only NonFata(scala.util.control.NonFatal) but in most cases this is what you do want.
import scala.util.Try
def wrapper(predicate: => Boolean) : Boolean = {
Try(predicate) getOrElse false
}
Or another way (For example if you really do want to catch any Throwable)
import scala.util.control.Exception._
def wrapper(predicate: => Boolean) : Boolean = {
catching(classOf[Throwable]) opt predicate getOrElse false
}
Scala provides Try feature, which is intended to be used in this occasions.
Notice that keeping your current wrapper leads to potential several errors. When you get a false result, you cannot know if it came from an application exception or a simple false evaluation. Thus, you can't properly handle any exception in your system, which may lead to multiple inconsistencies. Moreover, when you get a false result, your application internal state could be considered as unknown, making it very difficut to look into the box to know if the cat is dead or alive.
To solve this, scala's Try feature will handle this possible states for you, returning -in your case- a Success(elem: Boolean) in case your predicate effectively executes, and a Failure(ex: Throwable) in case an exception was thrown during execution. Then, you can use pattern matching to find out which was the case:
import scala.util.{Try, Success, Failure}
[...]
Try(predicate) match {
case Success(bool) => bool
case Failure(ex) => /* Do something to handle ex */
}
This somehow eliminates the need of your wrapper, for you can keep Try's result and then either match it or get it's result whenever you need to. And, as seen in previous answers, there is a rather complete set of operations you can use to handle all this cases in a more fashionable way.

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