DEV Community

Briggs Elsperger
Briggs Elsperger

Posted on • Edited on • Originally published at briggs.dev

Early Return Pattern

Early Return Pattern

People new to programming sometimes struggle to understand returning early inside a function, especially early beginners when coming from a language like Ruby, which has implicit returns. Today we're going to explore what an early return is, and what it can be used for in the context of JavaScript.

Understanding return

To understand what an early return is, you must first understand what return does in a function. Put simply, return returns a value from the function; it could be anything. In JavaScript you can return anything- a string, an object, or even another function. When a return statement has been found, the function ends immediately and returns the value to whatever called the function.

function timesTwo(x) {
  return x * 2;
}

console.log(timesTwo(21));
Enter fullscreen mode Exit fullscreen mode

In this example you would expect 42 to be logged to the console, and you'd be correct. The timesTwo function returned the result of x * 2 to console.log, and console.log printed the value to the console.

Early Returns

An early return is a return statement that is placed before some other code has been run.

function notFunkyFunction() {
  console.log('... And just when, it hit me, somebody turned around and shouted:')
  return
  console.log('Play that funky music white boy');
}

notFunkyFunction();
Enter fullscreen mode Exit fullscreen mode

This function will only log '... And just when, it hit me, somebody turned around and shouted:' and will never log 'Play that funky music white boy' due to the return statement. Using this, we can do some neat things to make our code look cleaner.

Early Return pattern

Since we can use a return statement to end a function immediately, we can take advantage of it. Let's look at a traditional if else statement and how one might convert it to the early return pattern.

function healthBarColor(health, maxHealth, hasShield) {
  const percentLeft = (health / maxHealth) * 100;

  if (hasShield) {
    return 'blue'
  } else if (percentLeft < 15) {
    return 'red';
  } else if (percentLeft < 60) {
    return 'yellow';
  } else {
    return 'green';
  }
}

console.log(healthBarColor(30, 124, false));
Enter fullscreen mode Exit fullscreen mode

In this case, we will find the value 'yellow' in the console. This looks OK, but it can be cleaner with the use of an early return. Let's refactor healthBarColor to use this pattern now.

function healthBarColor(health, maxHealth, hasShield) {
  const percentLeft = (health / maxHealth) * 100;

  if (hasShield) { return 'blue'; }
  if (percentLeft < 15) { return 'red'; }
  if (percentLeft < 60) { return 'yellow'; }
  return 'green';
}

console.log(healthBarColor(30, 124, false));
Enter fullscreen mode Exit fullscreen mode

This code is functionally the same as the code above, but it is arguably more readable and is shorter. This works because when we return from a function, the function ends then and there and gives us the value we desire. We can clean this up even more though, with a quirk of JavaScript. In JavaScript, if you have an if statement that is one line, you can omit the curly braces ( { } ). That would look like this:

function healthBarColor(health, maxHealth, hasShield) {
  const percentLeft = (health / maxHealth) * 100;

  if (hasShield) return 'blue';
  if (percentLeft < 15) return 'red';
  if (percentLeft < 60) return 'yellow';
  return 'green';
}

console.log(healthBarColor(30, 124, false));
Enter fullscreen mode Exit fullscreen mode

Now we have some clean, and easy to understand code that is still performant.

Gotcha!'s

Although the early return pattern can be very clean, there are times where it is contraindicated, mainly in non-functional style functions.

function attackedHandler(damage) {
  const armorStrength = getArmorStrength();
  let damageValue;

  if (damage > armorStrength) damageValue = calculateDamage(damage, armorStrength);
  if (damage === armorStrength) damageValue = damage - 10;
  if (damage < armorStrength) damageValue = 0;

  applyDamage(damageValue);
  setArmorStrength(damageValue);
}
Enter fullscreen mode Exit fullscreen mode

This looks clean, but is a bad idea because each if statement has to be evaluated, even if the first one is true. This technically isn't an early return pattern, but it does mimic it, even though it is bad practice. To fix this, you would have to use the standard if else statement.

function attackedHandler(damage) {
  const armorStrength = getArmorStrength();
  let damageValue;

  if (damage > armorStrength) {
    damageValue = calculateDamage(damage, armorStrength);
  } else if (damage === armorStrength) {
    damageValue = damage - 10;
  } else if (damage < armorStrength) {
    damageValue = 0;
  }

  applyDamage(damageValue);
  setArmorStrength(damageValue);
}
Enter fullscreen mode Exit fullscreen mode

Another time the early return pattern will not work is when you have to run code after the if else statement. The above code is a good example of this. If you were to return from the function within the if statements, the rest of the function would not run. This is called 'unreachable code' and would introduce bugs and logic errors in your program.

Conclusion

The early return pattern (have I said 'early return pattern' enough yet?), is a popular pattern and something you might see in other's code. Understanding why it's used and when to use it is important when it comes down to using it yourself. Now get out there and use this newfound knowledge to write better code!

P.S.

This pattern can be used with multi-line conditionals as well. The example below is perfectly fine:

function attackedHandler(damage) {
  const armorStrength = getArmorStrength();

  if (damage > armorStrength) {
    let damageValue = calculateDamage(damage, armorStrength);
    return takeDamage(damageValue);
  }

  if (damage === armorStrength) {
    return takeArmorDamage(damage)
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (9)

Collapse
 
i3uckwheat profile image
Briggs Elsperger

It's important to understand that removing something from code itself isn't always a good thing. However, it can be a useful tool to help clean something up when it's called for. It's another tool in the tool-belt, not an end-all.

I'd argue that ternaries, while being shorter, make it more difficult to read if-else chains in a lot of cases. However, that isn't always the case!

Collapse
 
devkiran profile image
Kiran Krishnan

Good one. I'm a fan of early return since I've started coding. It makes the code readable. In most of the cases, it can help you remove the else part.

Collapse
 
wisekingsullyman profile image
Austin Sullivan • Edited

I'm also a fan of early returns when used appropriately. When you have to check multiple conditions in your logic they can make the code a lot easier to parse at review time.

I do think that the value of early returning could be demonstrated a bit better though. For instance by showing how its usage can prevent having to check multiple conditions in each if.

 
i3uckwheat profile image
Briggs Elsperger

I'd agree if you're talking about larger scenarios that have more use-cases for this kind of thing, but often attempting to abstract can cause issues by adding complexity when it isn't necessary. When the need arises for abstraction, for sure, other patterns can be used. Often though, there is not a need to over-complicate or over-engineer something and selectively using something like this is useful. I did not mean to make it seem like this pattern is the END ALL of all patterns for returning data selectively from a function.

 
i3uckwheat profile image

Maybe the above example is not the best, it was simply used to outline the topic of the article.

I definitely agree that many conditionals are a sign that a different approach should be taken. I strongly disagree that this pattern should never be used however. Even if it's not the "most preferred" in a lot of cases.

However, I'll leave it up to the reader to decide which is easiest to read

Collapse
 
i3uckwheat profile image
Briggs Elsperger

With everything, it's another tool in the belt, however, it doesn't seem to be something to avoid. Evidenced by this popular style-guide: eslint.org/docs/rules/no-else-return

Collapse
 
jonrandy profile image
Jon Randy 🎖️

Interestingly, at university I was taught this was a bad idea and should be avoided

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Code readability and 'cleanliness' are purely subjective

Collapse
 
i3uckwheat profile image

Absolutely, which is why it's important to selectively apply patterns where it makes sense most.