# Algebraic Data Types

Algebraic Data Types are Objects in Functional Programming that give you a common interface to work with, and compose, data in a pure way. They are also one of the final steps you do to ensure you never have null pointers, or any Exception, ever again.

Let me say that again in a different way in case you missed that latter nuance:

Using ADT's will completely change your life for the better. They are the final tool you use to completely change how you program for the rest of your life. No more null pointers. No more runtime Exceptions. Mostly... again, we're in dynamic languages here, but we do our best.

# No Exceptions

We've covered how pure functions have rules that don't allow Errors. We've covered basic lenses and how they ensure no matter where your data comes from, you can ensure you won't get a null pointer if you dig in and access expected data to be there.

But what happens when your data isn't there? What happens when you make an HTTP call to a server and it fails? What happens when you attempt to parse bad JSON and it fails?

ADT's answer these questions, and give you tools to solve those problems. We'll cover 4 in this chapter, heavily ignoring their Category Theory roots.

# Maybe Data is There, Maybe It Isn't

My data might be there, but it might not be.

Examples include myList[2]. Maybe your Array has an item at index 2... maybe it doesn't. In that case, use Maybe. Either it's just a value, or it's nothing. So return Just('the value') or Nothing().

# All These Things Are Valid, or Some or All Aren't

The user is filling a ton of data into a form, and in a dynamic language, it's hard to ensure it's ok to send to all these pure functions without type checking. To provide a good user experience, I can't just say 'Something you submitted is bad, try again'. Instead, I need to know WHAT data is bad so I can update that form element.

Examples include a user's personal information on a form. Is their first name "Jesse" or "J" or "" or undefined because of a bug? What if you need to ensure all of their data is legit, and identify which ones aren't, so the UI can tell them. You can use Validator's to do this.

Another example on the server; the client is posting 5 parameters; I need to tell them which ones are good and which ones are bad for 4xx type errors to provide a nice to work with API.

Working with API's that don't surface what they don't like about the data you submitted is excruciatingly painful. Using a bunch of Validator's, you can solve both of the above problems.

Think of Validators as an Array; if everything is legit, you'll get an empty Array back called Success([]). If anything is awry, you'll get back an Array that has what is invalid and why, Failure(['First name cannot be blank.']).

# It Worked, or It Didn't and Here's Possibly Why

If I call JSON.parse, it may work... or blow up with a runtime exception. How do I make that pure?

For functions that may fail for reasons outside your control with possible information why they failed, return a Result. It's like a Promise, except synchronous. It worked? Cool, send back Ok(theJSON). Did it fail? Return an Error('reason why it failed to parse'). Note you return here, not throw. While it's sad you're never going to dance again, it's awesome you'll never use throw again in your code.

# Dude, So Many Things Can Happen...

I'm calling a downstream API in my application, and there are 5 different things it can possibly return: it worked, it failed and it's my fault, it failed and it's their fault, it partially worked, or it has no data. Do I use Result for that?

When you need to return multiple possible values, use Union. You make 'em up. Like Worked, YouFailed, TheyFailed, PartiallyWorked, or NoData. All ADT's can be thought of as unions. You return a type can be many possible types.

# Contain Data

Most pure functions you've seen up to this point take inputs of data and return modified data. ADT's are different; they contain data and hold on it just like Object's or Array's do. Functions typically know how to "take in an Array and give you a new, modified version of the Array back". Like OOP, however, ADT's have functions, or "methods", of their own to work with the data inside them and compose with other ADT's.

While dynamic programming languages don't have strong typing, they still have native types like Array and Promise that hold data and have conventions on how you use them. At runtime, those types are enforced. An Array is a list, I can add data to it like Array.push, get data out using numbers myList[0] or methods Array.pop, and construction methods like Array destructuring [...original, "new data to add"]. A Promise also wraps data in itself, you can get data out using then, and like Array's concat method, you can chain Promises together by returning a Promise in the then callback.

ADT's are useful just like Array and Promise are useful: Hold data, you can get data out, and depending on which library you use, all can be chained together in known ways.

This is also where dynamic languages start to become painful. Creating an Array or Promise is fine, but once you start chaining things together, it's hard to know "what comes out" without a compiler or intellisense in your IDE to help you. You probably saw this in the composing chapter. Algebraic Data Types have this problem as well once you start composing them together. You only really know if it works by running the code or having copious unit tests. Running the code early and often is a strength of dynamic languages, so just know "that's how it is". Still, they can add clarity of intent, help in data validation, and make it easier to work with data and errors in a pure way.