Practical Functional Programming in JavaScript - Error Handling
Tags: javascript, node, webdev, functional
Published: 2020-08-01 17:56:55

Hello. You've arrived at an entire post about error handling.

![https://imgs.xkcd.com/comics/error_types.png](https://imgs.xkcd.com/comics/error_types.png)

Comic Credits: https://xkcd.com/2303/

Today we'll talk about Errors in JavaScript functional programming. Errors are about setting expectations, and bugs happen when expectations miss reality. Proper error handling (both throwing and catching) is key to writing code with fewer bugs. In this article, we will explore current and historical methods for JavaScript error handling and attempt to settle on a good general way with current JavaScript syntax to handle Errors. I will also plug a function from my library at the end (with good reason, of course).

Without further ado, let's see what is currently happening with errors in JavaScript functional programming

 * [Elegant error handling with the JavaScript Either Monad](https://blog.logrocket.com/elegant-error-handling-with-the-javascript-either-monad-76c7ae4924a1/).
 * [Functional Error Handling](https://medium.com/techtron/functional-errors-handling-1d1b4688769d)
 * [Functional Programming in TypeScript](https://calebharris.github.io/fp_book_club_ts/chapter_4.html#the-either-data-type)

Feel free to click into these yourself, but I'll save you the trouble - all three articles say something along the lines of "stop throwing errors, instead use the Either monad".

Usually I don't think replacing an part of the language is a good way to go about things, unless the replacement offers something substantially better. Let's make our own judgment by exploring monads. [What is a monad](https://en.wikipedia.org/wiki/Monad_(functional_programming))?
> a monad is an abstraction that allows structuring programs generically while automating away boilerplate code needed by the program logic.

Moreover, monads [have a spec](https://en.wikipedia.org/wiki/Monad_(functional_programming)#Definition). A monad is defined by
 * a type constructor - something with a prototype

 `function MyMonad(x) {...}`

 * a type converter - a way to get a value into a monad

 `MyMonad.of = x => new MyMonad(x)`

 * a combinator - a way to combine multiple instances of a monad

 `myMonad.chain(anotherMyMonad) -> combinedMyMonad`

Now for Either. Here's a minimal Either monad implementation:

```javascript
function Left(x) {
  this.value = x
}

function Right(x) {
  this.value = x
}

function Either(leftHandler, rightHandler, x) {
  return x.constructor === Left ? leftHandler(x.value) : rightHandler(x.value)
}
```

Here's how you would use the Either monad.

```javascript
// parseJSON(s string) -> Either<Left<Error>, Right<Object>>
const parseJSON = s => {
  try {
    return new Right(JSON.parse(s))
  } catch (err) {
    return new Left(err)
  }
}

Either(
  err => console.error(err), // Left
  parsed => console.log(parsed), // Right
  parseJSON('{"a":1,"b":2,"c":3}'),
) // { a: 1, b: 2, c: 3 }
```

The way with the Either monad certainly looks pure, but is it really any better than a `try` `catch` block?

```javascript
try {
  const parsed = JSON.parse('{"a":1,"b":2,"c":3}')
  console.log(parsed)
} catch (err) {
  console.error(err)
}
```

Directly above is a vanilla JavaScript `try` `catch` block that does everything the Either monad does in the previous example. The snippet above does not require a `parseJSON` function for Left and Right monads, and is generally more concise. I do not see the benefit of the Either monad when there is already `try` `catch` blocks and `throw`. My opinion is the Either monad doesn't pull enough weight versus regular JavaScript syntax for any serious use. However, I do like that the Either monad promotes a functional style.

There is a similar shortcircuiting pattern to the Either monad in asynchronous callback handlers.
```javascript
function asyncFunc(userID, cb) {
  getUserByID(userID, (err, user) => {
    if (err) {
      cb(err) // new Left(err)
    } else {
      cb(null, user) // new Right(user)
    }
  })
}

asyncFunc('1', (err, user) => {
  if (err) console.error(err) // Left
  else console.log(user) // Right
})
```

Left and Right are baked into the syntax of callbacks. If err, do the Left thing, else do the Right thing. This worked well for callbacks, but when Promises came out, a lot of people moved on.

```javascript
const promiseFunc = userID => new Promise((resolve, reject) => {
  getUserByID(userID, (err, user) => {
    if (err) {
      reject(err) // new Left(err)
    } else {
      resolve(user) // new Right(user)
    }
  })
})

promiseFunc('1')
  .then(user => console.log(user)) // Right
  .catch(err => console.error(err)) // Left
```

Promises are eerily similar to the Either monad. It's as if Promises were Left, Right, and Either rolled up into one. The thing about Promises though is that they were not created for the sole purpose of expressing a Left and a Right path. Instead, they were created to model asynchronous operations, with left and right paths necessitated by design.

With async/await, we have the latest in error handling
```javascript
try {
  const user = await promiseFunc('1')
  console.log(user) // Right
} catch (err) {
  console.error(err) // Left
}
```

With the latest `async`/`await` syntax, the `try` `catch` block is the [current prescribed way](https://javascript.info/async-await#error-handling) to handle errors. If you're happy with `try` `catch` blocks, you could stop reading here and be off on your merry way. However, before you go, I should mention there's a clean way to handle errors via a library function (authored by yours truly). Hailing from my functional programming library, rubico, it's **tryCatch**!
```javascript
/*
 * @synopsis
 * <T any>tryCatch(
 *   tryer (x T)=>any,
 *   catcher (err Error, x T)=>any,
 * )(x T) -> Promise|any
 */

tryCatch(
  async userID => {
    const user = await promiseFunc(userID)
    console.log(user) // Right
  },
  err => console.error(err), // Left
)('1')

tryCatch(
  jsonString => {
    const parsed = JSON.parse(jsonString)
    console.log(parsed) // { a: 1, b: 2, c: 3 }
  },
  err => console.error(err),
)('{"a":1,"b":2,"c":3}')
```

rubico's `tryCatch` is cool because it catches all errors, synchronous or asynchronous. I personally like it because I like only needing one interface to handle all kinds of errors. One could argue that `try` `catch` with `await` would do the same thing, but at that point you're already in Promise land and cannot go back to synchronous land. rubico's `tryCatch` will behave completely synchronously for a synchronosly thrown Error. The sync vs async Promise correctness of rubico might seem insignificant at first, but it really is nice in practice for this to be a guarantee and not have to worry about it. If you would like to start functional programming on a similar level of bliss, check out [**rubico**](https://github.com/a-synchronous/rubico) today.

Finally, I love monads. I think they're super cool, but they should only be used in places where they actually do something better than you could with vanilla JavaScript. Using monads for the sake of using monads is, well, meh. My belief is JavaScript has its own class of monads - monads that benefit the multi-paradigm language that is JavaScript. If you know of such a monad, I would love to hear about it in the comments.

Thanks for reading! This concludes my series _Practical Functional Programming in JavaScript_. You can find the rest of the series on rubico's [awesome resources](https://github.com/a-synchronous/rubico#awesome-resources). If you have something you would like me to blog about, I would also love to hear it in the comments.

Cover photo credits:
https://resilientblog.co/inspirational/quotes-about-mountains/

Sources:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
https://en.wikipedia.org/wiki/Monad_(functional_programming)
https://en.wikipedia.org/wiki/Kleisli_category