In the previous articles we saw why avoiding side effect is an important part in achieving a pure function with all the benefits that are related to it, today we are going to see how to manage those side effects.
Usually developing a piece of software requires us to encode business logic in the code, that the first scope any dev is facing will be facing , but soon enough we are facing another scope specific to the code :
Although addressing the first scope will result in a software that meets the business requirement, we need to address the 2nd scope to get a reliable code.
An instinctive solution is just to handle them locally, lets say you have a function where a division by Zero might happen, handling the exception inside the function might be the straightforward way to do it: throwing an exception, doing so increase the mental load as we need to remember that a this specific function might throw an exception.
Lucky we are, Scala happens to offer infrastructure to cope with side effects called effect type, we are going to view some of them here:
Future: as discussed previously asynchronous actions are a side effect since we don’t have control on when these action are gonna be completed
Scala offers us a Future[A] as a type to cope with this kind of situation, it represents a computation that runs in a separate thread and use the callback.
NB: for the future to work it needs an execution context to manage the thread pool, we usually make use of the default Scala.
NB2: Future might not be the best container as it is eager, more on this in the next posts…
Either: Let’s first talk about Try :
The Try type represents a computation that may either result in an exception, or return a successfully computed value. scala-lang reference
lets see an example
def functionalDivision(n1: Double, n2: Double): Try[Double] = if(n2 == 0) Failure(new RuntimeException("Division by zero!")) else Success(n1/n2)
Try is used to pass both the value in case of success and the exception if failure.
What we would like to pass is not the exception but the reason for the exception , Try needs a subclass of throwable, thats where Either gets in :
def functionalDivision(n1: Double, n2: Double): Either[String, Double] = if(n2 == 0) Left("Division by zero!") else Right(n1/n2) println(division(1, 0)) //Left("Division by zero!") println(division(0, 1)) //Right(1.0)
Either offer us a way to pass both the error or the result, passing the responsibility to handle faulty execution path upwards