Use labels to break ifs in JavaScript(rthor.is)
rthor.is
Use labels to break ifs in JavaScript
http://rthor.is/javascript/quick-tip-labeled-ifs/
9 comments
To the contrary, labels and breaks are the better design because they are far clearer than testing for termination in each outer loop. Get more than two loops deep and your problem suddenly becomes unmanageable without labels and breaks.
However, if there are other actions like logging or reporting that are occurring it may be better to not use them. Here's some Ada:
However, if there are other actions like logging or reporting that are occurring it may be better to not use them. Here's some Ada:
Outer: loop
Inner: loop
Handle_Head: declare
Head : Human_Head;
begin
Acquire_Head (Head); -- Entry will block until head is acquired.
exit Inner when Head = No_Head;
exit Outer when Head.Exploded;
Log ("Head unexploded.");
exception
when Brain_Error =>
Log ("Brain deficiency detected.");
end Handle_Head;
end loop Inner;
Log ("Head exploded.");
end loop Outer;I'd argue that if you're more than 2 loops deep then you should, as I stated before, seriously evaluate your design decisions.
And, should you do so and end up in the same place, you may have stumbled upon that 0.1% of the time that I left wiggle room for in my first claim.
And, should you do so and end up in the same place, you may have stumbled upon that 0.1% of the time that I left wiggle room for in my first claim.
This method of breaking loops from the inside reminds me of the code obfuscation referenced in the HDD Hacking article [1]. Making code hard to read definitely seems like one use of this technique.
So I suppose the converse is true -- if you want your code to be easily readable, refactoring is a better way of solving the problem than label-loop-terminating.
[1]https://news.ycombinator.com/item?id=6148347
So I suppose the converse is true -- if you want your code to be easily readable, refactoring is a better way of solving the problem than label-loop-terminating.
[1]https://news.ycombinator.com/item?id=6148347
You know, returning from within the loop counts as breaking out of it too.
I get the feeling that your experience as a programmer is very different from mine.
I get the feeling that your experience as a programmer is very different from mine.
I'm having a hard time finding a reason to use this, I've always understood named breaks and named gotos as antipatterns, and MDN recommends you not use them as much as possible (if nothing else because they're uncommon). https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
The irregularity of these functions are not lost on the author, who improperly claims the following code is equivalent:
myTest: if ( condition ) {
if ( condition ) {
if ( !anotherCondition ) {
While the second comment will run for the same value of "anotherCondition," in the first, "condition" also must be true, and the second does not evaluate "condition" to run the comment.
The irregularity of these functions are not lost on the author, who improperly claims the following code is equivalent:
myTest: if ( condition ) {
// some code...
if ( anotherCondition ) break myTest;
// more code if anotherCondition is falsy...
}if ( condition ) {
// some code...
}if ( !anotherCondition ) {
// more code if anotherCondition is falsy...
}While the second comment will run for the same value of "anotherCondition," in the first, "condition" also must be true, and the second does not evaluate "condition" to run the comment.
EDIT: That this JS feature lets the developer break an outer scope from an inner scope is pretty awesome. I should ponder whether I can conjure this in C...
====
I'm with you. Now, take the case of a function that can return "early" - because it hit a condition that prevented it doing its job, or because it finished early on in its code. I've recently been requiring such functionality in places that have accumulated resources which should be released or otherwise tidied before returning. My fellow co-workers have been using goto, and at the label freeing the resources. My solution is to use 'while' and break (you could certainly use 'for' instead):
====
I'm with you. Now, take the case of a function that can return "early" - because it hit a condition that prevented it doing its job, or because it finished early on in its code. I've recently been requiring such functionality in places that have accumulated resources which should be released or otherwise tidied before returning. My fellow co-workers have been using goto, and at the label freeing the resources. My solution is to use 'while' and break (you could certainly use 'for' instead):
struct some_object *o = some_object_create(); // maybe you alloc here, and set properties
OtherType *result = NULL;
while(true) {
if (cond_based_on_args) {
result = OtherTypeCreate(...);
}
if (!result) break;
if (OtherTypeGetValue(result) != kCorrectValue) {
OtherTypeFree(result);
result = NULL;
break;
}
/* Other work to do with 'result' */
break; // never let it run again
}
some_object_free(o);
return r;
This code is a bit contrived, but I think it illustrates the idea.I would use Promises to handle the situation of "returning early." Essentially, you create recursive function, and execute it in a setInterval (don't forget to bind the scope if you're doing class references!). Manage state outside the scope of the function and create a deferred object outside the scope as well. When it's done, resolve the promise and kill the .
Elsewhere, use the resident "when" function to capture the resolved state. This helps create a very secular structure of code where each method is purposeful.
Elsewhere, use the resident "when" function to capture the resolved state. This helps create a very secular structure of code where each method is purposeful.
One debatable potential improvement to your alternative could be to use the `do { } while(false)` idiom - that removes the need to preserve the terminating break (and the chance of it being accidentally removed).
The reason to use it when you have a lot of conditional behavior tied to processing that can stop a process. With traditional code you have really two choices: highly-nested conditionals (or lots of utility subroutines) or using thrown errors for process control (which isn't their purpose). With labels, you're using process control for process control. In my experience, labels generally come into play for data processing, where often the desired behavior is not known until substantial decoding occurs. For made-up instance:
var rec = dataStream.next() // Stream sorted by lastName
processAtoM: while(rec) {
// Stop at N's
var lastName = rec.person.lastName.toUpperCase();
if(lastName === 'N') break processingLoop;
processRecord: do {
// We don't want deleted records.
if(rec.deleted === true) break processRecord;
// We don't want employee senior management, contractors or founders.
var employeeType = Persistence.employeeType.find(rec.company.employeeType);
if(['senior management', 'contractor', 'founder'].indexOf(employeeType) !== -1) break processRecord;
// Management was never sane about history structures.. FML
var history = someWackyDataStructureProcessThatIsPrettyIntensive(rec);
// At least I can be functional with this part.
var totalPromotions = _.reduce(history, function(total, item) {
if(item.promoted || item.lastPromotion !== undefined) {
total += 1;
}
return total;
}, 0);
// After people with 2 or more promotions
if(totalPromotions < 2) break processRecord;
// More conditions..
// Finally, this is still an interesting record.
var outputRec = someFormattingProcessToOutputFormat(rec);
outputStream.write(outputRec);
} while (false);
rec = dataStream.next();
}I would probably only use labels for breaking out of nested loops, for example: https://gist.github.com/badsyntax/5317545
I've been programming in JS since early 2000 and I've only ever used it to break out of nested loops.
I've had the experience of using labels exactly 1 time so far, in this code: https://gist.github.com/RSully/5262735
Dijkstra is turning over in his grave.
I'm surprised. I've always thought of labels as something to be used with goto. What is the purpose of labels in javascript, since it does not implement goto ?
Do you have any idea if it was intended to be used as you describe ?
Do you have any idea if it was intended to be used as you describe ?
The best I can come up with is this:
ANIMAL: if (isAnimal) {
DOG: if (isDog) {
POODLE: if (isPoodle) {
if (color == green) {
break POODLE; // we don't want green poodles
}
if (age > 10) {
break DOG; // we don't want old dogs
}
if (weight > 20) {
break ANIMAL; // we don't want heavy animals
}
// more poodle conditions
}
// more dog conditions
}
// more animal conditions
}[deleted]
Several languages support labels with "break" and "continue". It's mostly useful to break out several layers at once (nested loops, etc).
See for example Java: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/bra...
See for example Java: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/bra...
Interesting, but I'd probably need 10 seconds more to understand code that uses this than code that doesn't use it. I'm wondering if there is a real benefit to this.
I knew this trick from C++. And while it's a fun example, I believe it ruins the natural flow of your code. So please don't.
99.9% of the time, when I'm writing nested loops and I find myself needing the ability to kill the outer loop from within the inner loop, this is a flag that I need to refactor or re-evaluate my design, not start using labels and breaks.