Solvedjavascript What is the point of the no-continue rule?

The official ESLint docs say "When used incorrectly it makes code less testable, less readable and less maintainable."

Does Airbnb agree with the above reasoning? If so, can you give an example of how continue makes code less testable and less maintainable?

(I'm not arguing against it btw, just want to understand why.)

39 Answers

✔️Accepted Answer

@MegaArman
Loops are still useful in 2018 in many non trivial cases and will stay useful even in 2118, you can't do everything with map, reduce, filter.

See the example I gave above and tell me how continue is "bouncing around" like goto is.

but imagine working on a large codebase with lots of loops and if statements with continues scattered about

That's an invalid statement, if the code already become such a mess, then not having continue and breaks won't help you, loops shouldn't be huge, just like functions shouldn't be huge.
Banning basic coding concepts isn't a magic tool to make code more readable and maintainable, and oftenly can make the code even less maintainable (like more complex stopping conditions in no continue loops)

Other Answers:

continue is generally not used with a label. I think eslint needs to differentiate GOTO label usage from bare continue usage. When used without a label, continue is no different than a return statement in the body of a forEach loop.

I am going to disable this rule for my project. Would you be interested in added granularity for the no-continue rule if I proposed it?

Continue is not goto. That's like saying loops are goto.

SelaO: Continue is not goto. That's like saying loops are goto.

ljharb: no, it's not like saying that. Loops that use break or continue are goto.

Lets look at an example.

Using continue:

for (let item of array) {
  if (item == 0) {
    continue;
  }
  console.log("Found non-zero item");
}

Using if:

for (let item of array) {
  if (item != 0) {
    console.log("Found non-zero item");
  }
}

I'm guessing you'd say that the continue example is like GOTO because: it snaps the point of execution (from line-3 in example 1 to line-2, for the next iteration)

The thing is, "snapping the point of execution" is also happening in example 2. You're "snapping the point of execution" from line 2 to line 4.

"Okay, but in the second example, your always snap in the same direction -- you always snap downward, to directly after the block's braces."

The thing is, you can make a similar statement about continue: "Okay, but you always snap in the same direction -- you snap upward, to the first line of the loop."

In other words, both continue statements and if statements snap execution, and they do so in a consistent way: one always snaps up, the other always snaps down.

Conclusion: I don't see how the continue statement is significantly more "like a GOTO" than an if statement.
= = = = = = = = = =
The main argument I can see in response is this: "Both statements act consistently, however continue statements obscure readability more because sometimes the start of the loop is on a much higher nesting level than the continue statement, requiring more traversal to find the next executed line."

Okay, however:

  1. Many (if not most) times, usages of continue are done in simple if statements directly under the for loop, in which case you don't have to traverse through nesting levels -- so it's equivalent to an if-statement in how difficult it is to track the point of execution.
  2. Even in the nested cases where continue statements may yield worse readability (depends on how you'd have to restructure to avoid the continue), it's still an exaggeration to say "continue statements are GOTO" whereas "if statements are nothing like GOTO".

Both of them:

  • Snap the point of execution.
  • But they do so consistently.
  • With the programmer knowing unambiguously where the next line of execution will be. (without having to search for labels like with GOTO)
  • And with no chance of jumping to areas of code which have code prior to them that (misleadingly) have not yet been run. (which is one of the main problems with GOTO)

I'd like to see a list of properties of continue statements which make them equivalent to GOTO statements, which are not shared by loops or if statements. I know there are some, but I don't believe them to be substantial enough to say "continue is GOTO" but "if statements are nothing like GOTO".

continue is GOTO because it breaks the top-down flow of code execution

But a regular loop fits that description as well. When you reach the end of a for loop block, it breaks the top-down flow of code-execution -- you have to scan back up to the top of the loop to find the next execution point.

We don't consider loops (or forEach) to be as bad as GOTO though, and that's because:

  1. It's easy to find where the next line of execution is when you get to the end of a loop.
  2. Loops still ensure that any code above the current line has already been run, and has been run in order -- that is, you don't have to worry about having jumped forward with misleading code above it that hasn't initialized.

And continue has those same positive properties. With continue:

  1. It's easy to find where the next line of execution is: just return to the start of the loop.
  2. Any code above the current line has already been run; continue never causes you to jump forward "over" code. It works like a loop and merely lets you go back and re-run a block of code (with the next iteration of data), which is easier to reason about.

In other words, if continue is criticized as being GOTO merely because it breaks the top-down flow and transports you to an earlier line, then you have to also criticize for loops, forEach calls, and anything else that makes you re-run a block of code, because those either are or result in statements that jump to earlier lines of code. (such as return calls inside a function passed to forEach, which work almost exactly the same as continue calls)

If there is a different reason for calling continue an instance of GOTO, then it can be brought up, but so far I haven't seen a substantial one.

= = = = = = = = = =

You do add:

With continue, you exit the block prematurely, no longer evaluating further statements, and then proceed with the next iteration.

The concern here could be that, continue limits your ability to ignore earlier (seemingly unrelated) if-statement blocks, because you don't know whether that if-statement block contains a "continue" statement which will end up short-circuiting the for-loop block and keeping the code you're interested in from even being reached.

If that's the core reason that continue is criticized, then I can understand that. However, if that's the reason, then you also have to criticize having multiple return statements in the same function: just like when you add a continue statement, adding a 2nd or 3rd return statement makes it so you can't ignore those other if-statement blocks anymore. You have to make sure they don't contain a return statement that's going to short-circuit the function block before it gets to the code you're interested in.

Yet, the airbnb style guide indicates that it's fine to have multiple return statements in the same function. There are a few examples on the homepage, such as: https://github.com/airbnb/javascript#variables--define-where-used

// good
function checkName(hasName) {
  if (hasName === 'test') {
    return false;
  }

  const name = getName();

  if (name === 'test') {
    this.setName('');
    return false;
  }

  return name;
}

= = = = = = = = = =

In summary, I think there were two criticisms of continue statements that were brought up (as grounds for saying continue is GOTO):

  1. Continue statements break the top-down flow of code execution [like GOTO].
  2. Continue statements reduce your ability to skim over if-statement blocks, because those blocks might contain continue statements that short-circuit the loop's code [like GOTO].

My response was that:

  1. For loops, forEach calls, return statements in forEach functions, etc. all do the same thing and yet aren't criticized as being (or resulting in) GOTO statements because of it, so the criticism is inconsistent with our acceptance of this aspect for other constructs.
  2. Having multiple return statements in the same function does the same thing, and yet it's commonly used -- including in the airbnb guide itself. Furthermore, people don't call those extra return statements GOTOs based on it.

The reason #2 above I think is a fair criticism of (deeply nested) continue statements. But that doesn't mean it's the same as a GOTO, because there are several negative properties of GOTOs that aren't shared by continue statements. (a couple of these are listed at the start)

More Issues: