Hello, I saw the “Monad” concept at first time at TDC(São Paulo) 2016 at the functional programming Track. I didn’t get any use possibility in speech (maybe because I don’t know Haskell), but three months ago, when I started to work in a Java project with two collegues, a senior job colleague convinced me to use java.util.Optional in some cases along this project “It’s cool”, he said. He already worked with Scala using some monadics built-in tools, then he knows the monads advantages.
This project has many sequencial steps, the code majority has to validate something, convert to another type, save in database, send to a queue and so on. After many sprints interactions, when it started to take form, the code did everything needed keeping all things simple basically composing a lot of Functions applied in Java Optional Objects.
After that, when I came back to Ruby, I started to search some gem with the similar behavior, I googled it and I found Dry-Monads inspired by Kleisli. When I visited the Kleisli page I saw this phrase “You can use Haskell-like function composition with F and the familiar”, I thought “Oh my Gosh, I got Monads now”. Moments later, I found a cool post in Quora website about Monads, it’s different(and cool) because don’t envolves a huge number of mathematical formulas to explain the Monads concept, you can take a look here. He uses Haskell in examples, I don’t know Haskell but when if you compare to Dry-monads you will understand too.
Everyone that already programmed in Java, at least once, got an NullPointerException. This error occurs when someone call a function to null reference.
If we use Ruby:
Ruby return an exception when we try to call an inexistent attribute or method, but when we call ‘.to_s’ it returns a blank string. If we use Java, when we call any method to null, it will return an “NullPointerException”.
Since Java 8, we have the java.util.Optional, it can be useful in this case, to return an empty string when we use a null reference. Let’s see the example below:
It’s extremely useful to avoid Java NullPointerException. Another cool thing is the chain methods possibility, we can do it using some functions as ‘#map’ and ‘#flatMap’. We can also use the Optional behavior to avoid ‘if’ sequences and we can to turn our code more readable using the same text way. In Elixir we can chain methods using the pipe operator ‘|>’, let’s check it.
We can do it in Java too.
We used this behavior many times in our project than, in this post, I will try show a similar concept using Dry-Monads in a simple ‘Order’ example.
Ok, let’s start, Our very simple use case is:
First, we need an Order class
Ps:. I wrote all getter and setters to turn easier to understand.
And the Product class
Now, let’s check if works creating an Order and some products
Awesome, it works! But if we set discount as nil…
Oh :( it’s bad. Do you know what happen if at least one product has a nil price?
Is it easy to correct, right? We can add the code below to avoid these exceptions.
Magic, it’s works! but could we call an order without products?
Oh damn it, we can use the ‘||’ operator too or Array(value), but we can try something different using dry-monads. Let’s change the code!
We used Maybe in this case to get an Optional behavior. It will return None if we pass null or Some in non null cases as code below.
The bind function was used to apply a function in object. We can use it to do an Upcase like previously.
Then let’s try the new version
It’s works, but the total function isn’t readable, we can improve it, but first, take a look:
The total function has three responsabilities, it collects all products price, sum it and subtract the discount. We can break it into 3 separated functions, something like the code below.
The code above used a #fmap function, it works like the bind function but it wrap the result into Some. The #fmap function returns None if applied in a None object. It works like the example below.
It’s cool, but now we need to add another feature. If our order doesn’t has products, we don’t need to calculate the total in these cases, then we can add this behavior using the ‘Either mixin’. Let’s see how we can use it. We will create a new command class ‘Commands::Order::Total’ and use it to calculate the order price.
The Dry-Monads page describe Left and right as “The Right can be thought of as “everything went right” and the Left is used when “something has gone wrong.”. Left is something like an exception, then when we have a function that returns Left the next chain function isn’t executed. Right is used when we have an expected result, then it can pass to next chain function.
It works! but the code returns None, Some or Left in some cases. If we use only Left and right we can check if we had success or no. Another thing is the sum of prices can be negative, we can return an failure if it occurs. Let’s make some changes.
That’s all, Is it cool, right? If you like it you can check the page project here, there are many amazing features.