continue is kind of like goto. Are you familiar with break? It's easier to think about them in contrast:
breakterminates the loop (jumps to the code below it).continueterminates the rest of the processing of the code within the loop for the current iteration, but continues the loop.
continue is kind of like goto. Are you familiar with break? It's easier to think about them in contrast:
breakterminates the loop (jumps to the code below it).continueterminates the rest of the processing of the code within the loop for the current iteration, but continues the loop.
A continue statement without a label will re-execute from the condition the innermost while or do loop, and from the update expression of the innermost for loop. It is often used to early-terminate a loop's processing and thereby avoid deeply-nested if statements. In the following example continue will get the next line, without processing the following statement in the loop.
while (getNext(line)) {
if (line.isEmpty() || line.isComment())
continue;
// More code here
}
With a label, continue will re-execute from the loop with the corresponding label, rather than the innermost loop. This can be used to escape deeply-nested loops, or simply for clarity.
Sometimes continue is also used as a placeholder in order to make an empty loop body more clear.
for (count = 0; foo.moreData(); count++)
continue;
The same statement without a label also exists in C and C++. The equivalent in Perl is next.
This type of control flow is not recommended, but if you so choose you can also use continue to simulate a limited form of goto. In the following example the continue will re-execute the empty for (;;) loop.
aLoopName: for (;;) {
// ...
while (someCondition)
// ...
if (otherCondition)
continue aLoopName;
tree walker - How do I Interpret a Continue/Break Statement in a Loop? - Programming Language Design and Implementation Stack Exchange
Advice on defending the use of continue and break in a foreach loop in Java
The Java Loop Continue Control Statement - Explained with Examples - Guide - The freeCodeCamp Forum
Is it bad to use continue?
I use continues pretty often. Whenever they make sense, but not when they don't. I don't see it as bad programming practice, unless it effects readability for that particular context (which just depends on the function in question).
More on reddit.comVideos
Throw an exception
For a simple tree-walking interpreter in a language with catchable exceptions, both break and continue statements can be implemented as throwing a specific exception, while the loop sets up a try-catch to detect and handle them.
Consider this pseudocode implementation:
interpret_while(condition, body):
try {
while (evaluate(condition) is True):
try {
evaluate(body)
} catch (Continue) {
// do nothing, just go to next iteration
}
} catch (Break) {
// also do nothing, have already left the loop
}
interpret_continue():
raise Continue
interpret_break():
raise Break
We have two exception types and two try-catches, one inside the loop for continue and one outside for break. If there are nested loops, the innermost one will automatically catch the exception and produce the right semantics. The exception-handling system already innately deals with the necessary stack unwinding, exiting each layer of recursion until you get back to the right place.
This can also allow for labelled breaks: include the label in the exception, and test and re-throw if it doesn't match until it reaches the appropriate surrounding loop.
This is not going to be the most efficient or performant approach, but it's very straightforward to get moving with and leverages the functionality of the host system. A similar approach can be used to implement non-local returns or exception handling within the interpreted language, and those will fit in comfortably with one another.
Typically, you need to distinguish between what it means for a statement or expression to "complete normally" or "complete abruptly" (borrowing terminology from the Java Language Specification). An expression which evalutes to a value "completes normally", as does a statement which executes in a normal sequence. On the other hand, a statement or expression which has some effect on the surrounding control-flow "completes abruptly".
A statement or expression could complete abruptly if it:
- Returns a value from the enclosing function.
- Throws an exception.
- Breaks from or continues an enclosing loop.
So generally speaking, these are all handled the same way. A typical solution is to represent the result of a statement or expression as a discriminated union of these possibilities, for example in Rust you might write:
enum EvalResult {
Normal(Value),
Return(Value),
Throw(Value),
Break,
Continue,
}
(If you have labelled breaks and continues, or you allow constructs like let foo = loop { break 5; }, then your enum will need to account for those, too.)
Your "eval" function, which evaluates an AST node, returns a result like this. Then when evaluating a loop, you would check for these results and handle them appropriately:
match ast_node {
// ...
WhileLoop(cond, body) => {
loop {
let cond_result = eval(cond);
match cond_result {
Normal(v) => if !v.is_truthy() { break; },
_ => return cond_result,
}
let body_result = eval(body);
match body_result {
Normal(_) | Continue => continue,
Break => break,
Return(_) | Throw(_) => return body_result,
}
}
return Normal(VOID_UNIT);
},
// ...
}
Here I'm assuming is_truthy() converts a Value to a native Boolean in the host language, and VOID_UNIT is the value resulting from a statement which doesn't produce a "proper" value.
Note how we return cond_result or return body_result directly when it is necessary to propagate a control-flow effect that this loop isn't supposed to handle itself, for example if the loop body contains a return or throw statement. The same propagation will have to be done elsewhere, e.g. when you add two numbers together, you'll have to propagate control-flow effects from left_result and right_result, in order for those control-flow effects to end up being handled by the eval function for the correct AST node.
I like using the continue and break statements in my for each loops in Java. My CTO, doesn't like them, and suggests that "used outside of a switch statement, it gives you multiple return points from a block of code, and it – gives you GOTO like functionality". Are there any suggestions of arguing points that I can make, to defend this position... or is he right?