Use labels to break ifs in JavaScript
rthor.is
rthor.is
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.
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;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.
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.
I get the feeling that your experience as a programmer is very different from mine.
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.
====
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.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.
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();
}Do you have any idea if it was intended to be used as you describe ?
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
}See for example Java: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/bra...
The second if in the second piece of code should be:
if (condition && !anotherCondition) {