Ditching the "else" Statement
Tags: typescript, codequality, computerscience
Published: 2021-10-16 20:43:17

Are "else" statements really necessary? When first learning to program we are taught about "if" statements and "else" statements. If this condition is met do something, else do another thing. It's fundamental to nearly every programming language, but can we ditch the "else" statement?

## The Case for Ditching It

Like with most things in programming there will be scenarios where using an "else" statement is more appropriate than avoiding it, but let's assume that we want to ditch it no matter what scenario arises. How would we do that and why would we want to?

The best way to explore this approach is through examples so let's start with a simple one. All of the examples below are written in Typescript:

```typescript
// With "else"
const areEqual = (value1: string, value2: string) => {
  if (value1 === value2) {
    return true;
  } else {
    return false;
  }
};
```

```typescript
// Without "else"
const areEqual = (value1: string, value2: string) => {
  if (value1 === value2) {
    return true;
  }

  return false;
};
```

This is a common scenario where the "else" statement should be omitted because it is adding more code without adding value. Of course, this entire function is adding code without adding value, since you could just use the "===" operator directly, so let us complicate things a bit more. What if we don't want to "return" from inside our if block?

```typescript
const getFullName = (
  givenName: string,
  lastName: string,
  preferredName?: string
) => {
  let firstName = "";
  if (preferredName) {
    firstName = preferredName;
  } else {
    firstName = givenName;
  }

  return `${firstName} ${lastName}`;
};
```

There are several ways to get rid of that "else" statement which also improve the readability of the function. For example, a ternary can be used in these situations:

```typescript
const getFullName = (
  givenName: string,
  lastName: string,
  preferredName?: string
) => {
  const firstName = preferredName ? preferredName : givenName;
  return `${firstName} ${lastName}`;
};
```

This has the added benefit of letting us use a "const" instead of a "let", but wait a minute, this is cheating! A ternary is essentially an "if/else" statement with less syntax, so we didn't really ditch the "else" statement!

Let's try again:

```typescript
const getFullName = (
  givenName: string,
  lastName: string,
  preferredName?: string
) => {
  const firstName = getFirstName(givenName, preferredName);
  return `${fullName} ${lastName}`;
};

const getFirstName = (givenName: string, preferredName?: string) => {
  if (preferredName) {
    return preferredName;
  }

  return givenName;
};
```

That is much better, but for the minimalists out there you could also write it this way:

```typescript
const getFullName = (
  givenName: string,
  lastName: string,
  preferredName?: string
) => `${getFirstName(givenName, preferredName)} ${lastName}`;

const getFirstName = (givenName: string, preferredName?: string) =>
  preferredName || givenName;
```

The real sticklers will note that this could be done in one function and would reduce the lines of code and the number of characters used:

```typescript
const getFullName = (
  givenName: string,
  lastName: string,
  preferredName?: string
) => `${preferredName || givenName} ${lastName}`;
```

This is a great little function, but in combining the two functions into one the reusability has gone down. What if we only want to get the first name? We no longer have a dedicated function to do it! Of course in a real code base simply using the "||" operator to pick between the two values would be acceptable and would result in less code:

```typescript
const fullName = `${preferredName || givenName} ${lastName}`;
```

However, their is also a readability trade off since having a specific function makes it clear what operation is being executed. This along with the reusability is why the dedicated functions is preferred.

Alright enough talk about minimizing code, let's get back to the "else" conversation. However you choose to implement functions similar to those above, you do not need an "else" statement to accomplish the task. Both examples here show the two main ways to avoid using an "else" statement: "returning early" and "extracting smaller functions".

Returning early is a straight forward concept. The idea is to return your result (including void) as soon as you can, in other words, minimize the amount of code that needs to be executed. If we return early we can omit "else" and "else if" statements as they just become redundant.

Extracting smaller functions should be a familiar technique to most software engineers. In both Functional and Object Oriented Programming this is often referred to as the Single Responsibility Principle, the first of the SOLID Principles. We want our functions, classes, and methods to have a single purpose/responsibility. Many engineers make the mistake of defining a single responsibility with a scope that is far too big, resulting in classes, methods, and functions that are large and have many smaller responsibilities. Every large responsibility is made up of smaller responsibilities, and the more of those we identify and isolate, the closer we are following the Single Responsibility Principle.

Following these two techniques will result in fewer "else" statements without even trying. Sounds like if we write our code with good fundamentals we should never need an "else" statement, so why use them at all?

## The Case for Keeping It

The only real case for continuing to use "else" statements is convenience, and this is a pretty strong argument. Whether you are working within a legacy code base or just rushing to make a tight deadline, "else" statements are the last things on your mind. However, I still hardly use "else" statements. Not because I'm consciously thinking about it, but because I usually keep my functions small and single purposed, so the need for "else" statements rarely arises. From time to time an "else" statement or two isn't a big deal, but only when it's convenient.

So how often does this convenience arise? Unfortunately, very often, especially in legacy code bases. Finding an existing code base that is strictly following best practices and conventions is a rarity, and honestly that's a good thing for technological progress. Innovation lies somewhere between idealism and pragmatism, as does the decision to use an "else" statement or not.

## Conclusion

End of the day, do what is best for you and your team. Most legacy code bases I've seen have plenty of technical debt beyond the number of unnecessary "else" statements being used. I would however encourage everyone reading this to create a Standards and Conventions document for your team. Depending on the size and experience the team, the document may be very small with just enough detail to let the engineers know what is expected of them. For medium to large teams a document like this is essential and should be constantly referenced, maintained, and updated. The standards and conventions you add over time will show the progress that your team has made towards having a higher quality code base. Maybe you'll even include "No Else Statements" as a standard, but probably not.