14-day Cloud trial
Start today. For free.

One editor. 50+ features. Zero constraints. After your trial, retain the advanced features.

Try Professional Plan for FREE
PricingContact Us
Log InGet Started Free

Tiny Programming Principles: The concept of Optionals

February 8th, 2021

9 min read

People discussing at a table in an office

Written by

Millie Macdonald

Category

Developer Insights

This is another part of our series on Programming Principles with another functional programming method: the concept of Optionals. 

Functional programming prefers to use pure functions, avoid mutable data, and avoid side-effects, choosing methods that are more predictable, precise, and both easier to read and test. 

Unfortunately, a lot of JavaScript’s built-in concepts don’t fit well with functional programming and developers have to find alternative ways to make things happen. One example of this is null and undefined, and how to handle them. Many developers (including our team at Tiny) are now using Optionals (or similar concepts) as a good work around. 

But not everyone knows about Optionals. So, let’s take a closer look at what issues may come up, why they happen, and how you can use Optionals (or other alternatives) to write more stable, predictable, and usable code.

The problem with null or undefined

Worker says to boss

JavaScript normally requires your variables to have some kind of value attached to them like:

  • A number
  • A string
  • Null (something that doesn’t have a value)
  • Undefined (a variable you’ve declared but haven’t assigned anything to yet)

Null and undefined have several differences and similarities.

Null or undefined are usually used if you don’t have a value ready to assign yet, or if you explicitly want a variable to not have a value. This might happen in instances where you’re working with user input. Maybe you have a form with an input field where users can add their name. Until they’ve typed something and hit submit, any variable linked to that value would be null or undefined. Or if they skip over a field in the form and hit submit, that variable would remain null or undefined. In places where your code tries to use that value, you first need to make sure it’s an actual value by asking “is this value null or undefined”? If it has a value, your code can continue on. If not, you need to handle the fact that the value is missing. Depending on what your code does, this can result in a lot of if statements and branching. 

Here’s an example where the value is undefined: 

var testVar;
alert(testVar); //shows undefined
alert(typeof testVar); //shows undefined

Here’s an example where the value is null:

var testVar = null;
alert(testVar); //shows null
alert(typeof testVar); //shows object

These values are problematic for a few reasons.

First of all, having to repeat that null or undefined check every time gets pretty annoying. Most programming languages have one keyword that means “this doesn’t have a value yet”. Usually, they’ll have something like null or undefined, not both. Having to check both these values repeatedly can add bloat and complexity to your code. It also means more mental overhead when programming - you have to recognise where null and undefined might be problematic, and remember to add in the necessary checks to ensure they don’t break anything.

But most importantly, null and undefined can hide bugs or make them harder to figure out. You may need to track the value of a variable from its creation until the point the bug happens to figure out when the value changes. 

This gets even more complicated when you bring in all of JavaScript’s other quirks. For example, every possible value in JavaScript can be truthy or falsey.

Zero is falsey. 

One is truthy. 

An array is falsey. 

An object is truthy. 

Both null and undefined are falsy.

…it doesn’t make much sense. 

But it also means if you’re trying to compare two values and one of them is null or undefined, you might start getting unexpected results. Especially since JavaScript might cast one or both values to true or false when trying to compare them, causing unexpected behaviour.  If you hit this kind of problem, it can be very difficult to get to the bottom of what’s causing it. 

Young man looks confused

Overall, this is very un-functional programming, as there’s no way to be sure about what the outputs are going to be with constantly doing extra checks that can easily be forgotten.

Of course, null and undefined are just one of many things in programming (and JavaScript in particular) that just don’t make sense. If you haven’t already, check out this talk by Gary Bernhardt from CodeMash 2012 - it sums things up perfectly (and might give you a laugh).

That’s where Optionals come in

To replace null or undefined and avoid the mess that comes with it, we use Optionals as a replacement. 

What are Optionals?

An Optional is a data structure that has an optional value. More strictly, an Optional can either have a value or nothing - it must be one or the other. This forces you to handle both cases - you can’t forget like it’s so easy to do with null and undefined values.

That means instead of making a variable that starts out as “undefined”, you make a variable and say it’s “option none”. Then later on, once you get a value for the variable, you make it an “option some of the value” which wraps it up nicely. 

// Example: 
// Tiny’s Optional.from() returns a none if given null or undefined, else returns a some of the value
// isSome() returns true if the variable is a some, or false if it is a none
// getOr(fallback) returns the value if the variable is a some, or the fallback argument if it is a none

var foo = Optional.some(“hello”); // foo is a some of the value “hello”
foo.isSome(); // returns true
foo.getOr(“fallbackValue”); // returns “hello”

var bar = Optional.none(); // bar is a none
bar.isSome(); // returns false
bar.getOr(“fallbackValue”); // returns “fallbackValue”

Unfortunately, Optionals aren’t built-in to JavaScript, so to use them you have to implement them or use a library. Fortunately, they are a very common feature of various functional programming languages, so it’s easy to find information about them. Though here are many other names for what we at Tiny call Optionals - “Maybe”, “Either” or just “Option” are some other common names. In fact, until recently, our Tiny development team referred to them as “Options” before changing the name as part of a big overhaul on one of our APIs. 

Why use Optionals?

Optionals are a great alternative to using null or undefined for variables that don't yet have values for two main reasons:

1. Robustness

They’re essential for functional programming because they clearly denote variables whose value is optional, forcing you to handle - or at least think about - both the case where they do and do not have a value.

Unlike with a variable that might be null or undefined, where you are able to operate on the variable without checking what it is (which, if you forget to check, might cause bugs), with Optionals you have to check if it has a value before operating on it. 

At the end of the day, it decreases the chance you will have bugs caused by values not existing when they should - or vice versa.

2. Readability

Optionals improve readability because if you see that a variable is an Optional, especially if you are using types, you can know at a glance that it might not have a value (yet), and that you may have to handle both the case where it has a value and where it doesn’t. This can remove the need to track variables through code to figure out what values they might have at different points.

If you are strict about using Optionals, and not allowing null or undefined values, you can also know at a glance that any variable that isn’t an Optional must have a value at all times, which can further improve readability.

Optionals - and the helper functions you can use with them - can make your code less verbose, too, which is always nice.

Do you still need null and undefined in JavaScript?

Null and undefined are built-in core features of the language, which means that some JavaScript methods will return them, no matter what. So, sometimes you can’t avoid them completely or make them illegal. However, you can outlaw them in the core of your code. For example, by wrapping anything that has to return null or undefined so that it returns an Optional instead.

That said, my team and I avoid null and undefined as much as possible. It does mean using a library that implements Optionals, and teaching new hires how to use them, but to us the benefits are worth it.

However, if you don’t want to jump all the way to Optionals, there are other alternatives out there…

Other alternatives to null and undefined

A good first step is to avoid assigning null or undefined to variables in your code, and only dealing with null or undefined when they are introduced by built-in JavaScript methods or third-party code. There have also been a few recent additions to JavaScript that make avoiding null and undefined easier than ever, like:

1. Optional chaining

Optional chaining (?.) allows you to read a property’s value within a chain of connected Objects, without needing to validate each reference in the chain. 

2. Nullish coalescing operator

Nullish coalescing operator (??) is a new short-circuiting operator that returns its right-hand operand when its left-hand operand is null or undefined, otherwise returning its left-hand operand. It’s a good alternative to the logical OR operator (||) if you specifically want to check for null or undefined, since logical OR checks for any falsey value. It can also be a good shorthand syntax for selecting the first defined value from a list of values that might be null or undefined.

3. Default parameters

Default parameters enable you to say “if this is undefined, use this instead” when passing something into an argument. Note that this does not work with null though - null will be passed through as a valid value.

4. Promises

If you're dealing with async data, Promises may also be a helpful alternative as they have similar concepts of "has a value" and "doesn't have a value". They’re mainly used for asynchronous actions like calling to a database and waiting for the value to return though - in other words, things that might take time. And Promises can come with more overhead, which you may not want for simpler use cases.

If you find that the above alternatives aren’t enough, and that you’re either having to check for null or undefined a lot… you may save more time by using Optionals.

Try out Optionals using Tiny’s open source library!

If you’re sick of the null and undefined mess, maybe it’s time to try something different? 

Changing the way you do things will take some work, but consider how much work you’re already put into managing the null/undefined mess with:

  • The mental overhead of having to remember to check for null and undefined when writing and reviewing code
  • The code bloat of having to implement checks for null and undefined everywhere they might cause problems
  • Time lost tracking down and fixing bugs caused by variables being in an unexpected state

If you’re ready to try Optionals in your code, you can check out Tiny’s Katamari, which is one of our libraries of utility functions. But, be warned, we are in the middle of changing our Optionals implementation a lot, so you might prefer to try fp-ts as an alternative in the meantime. 

Let’s continue the discussion

Want to share/rant about your experience with null or undefined? Or share how you’re using Katamari in your project? We’re always up for a chat on Twitter at @joinTiny!

And if you’re looking for more ways to improve the way you do programming, check out previous blogs in our programming principles series:

Javascript
byMillie Macdonald

Millie is a JS developer and leads the core editor team at Tiny. She specialises in crazy things like copy and paste, image handling, and tables, and occasionally gets to play with ReasonML. She's also an esports community manager and tournament organiser in her spare time.

Related Articles

  • Developer InsightsMar 7th, 2024

    Understanding Uncaught TypeErrors in JavaScript

Join 100,000+ developers who get regular tips & updates from the Tiny team.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Tiny logo

Stay Connected

SOC2 compliance badge

Products

TinyMCEDriveMoxieManager
© Copyright 2024 Tiny Technologies Inc.

TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.