DEV Community

[Comment from a deleted post]
Collapse
 
jon49 profile image
Jon Nyman • Edited

I've been loving this series and the comments that have been made.

There is actually a better way that makes handling errors easy, not tedious, and explicit. F#, which brought the programming world the async/await pattern which makes asynchronous coding seem like procedure coding through its computation expressions.

In other other languages the language itself has to change in order to add async/await. But F# has computation expressions which you can think of as something similar to macros in some languages, but definitely different.

So, to get to the point, in F# you can take these wrappers (monads) and make the code appear to be imperative, which makes it easier to understand and use. So, in your example it would look like this in f#:

let routeInvoiceSend (c : Routing.Context) =
    let invoice = c.Invoice
    result {
    let! requestedEmails = c.Request.Emails.Parse()
    let! validatedEmails = validateEmails requestedEmails
    let! client = database.FetchClient invoice.ClientID
    let! pdf = renderPDF invoice
    return! requestedEmails |> sendEmailWithAttachment pdf |> reduceResult
    } |> // check for errors and respond success or (friendly message and log) failure to user

Note that none of those steps will continue on if there was an error. They just go straight to the end once there was an error.

I think Go seems like a pretty cool language. I would love to just create a single tiny binary at the output. But computation expressions make F#, among other things, such a joy to program in that I have a hard time leaving it. I'm not trying to get you to start programming in F#. I'm just trying to show that there are better ways out there. Maybe one day Go will adopt a better pipe line for error handling. But it does use a monadic structure, which is pretty cool.

 
jon49 profile image
Jon Nyman

And to be clear, the wrapper itself is not the monad, it is the implementation of bind over the wrapper that is the monad. So, Go doesn't actually implement a monad, it just implements the wrapper. All it needs to do is implement bind and then you would get more elegant code.

 
jon49 profile image
Jon Nyman

And it just occurred to me (I'm getting pretty tired) that the reason Go doesn't make it simpler is because the creators of Go refuse to implement generics for the language. Which is unfortunate, since if you had generics you would be able to bypass some of this tedium in coding.