views:

562

answers:

14
+5  Q: 

for each ... break

I feel dirty every time I "break" out of a for-each construct (PHP/Javascript)

So something like this:

// Javascript example

for (object in objectList)
{
   if (object.test == true)
   {
      //do some process on object
      break;
   }

}

For large objectLists I would go through the hassle building a more elegant solution. But for small lists there is no noticeable performance issue and hence "why not?" It's quick and more importantly easy to understand and follow.

But it just "feels wrong". Kind of like a goto statement.

How do you handle this kind of situation?

+18  A: 

I use a break. It's a perfectly cromulent solution.

Paul Tomblin
+1 for use of the word "cromulent."
Samir Talwar
`cromulent`! i like it
Rakesh Juyal
What I like about "cromulent" is that it means what it is - a word that's perfectly obvious what it means from context.
Paul Tomblin
By that argument, you could clarify the sentence even further by removing the word and just leaving the context. Saves bytes too!
Leigh Caldwell
@Leigh: "It's a perfectly solution" ?
fretje
I accepted your answer purely for teaching me a new, albeit pop-cultered, word.
ChronoFish
I'm happy to embiggen your vocabulary.
Paul Tomblin
+1  A: 

I really don't see anythign wrong with breaking out of a for loop. Unless you have some sort of hash table, dictionary where you have some sort of key to obtain a value there really is no other way.

JonH
+1  A: 

I'd use a break statement.

Tordek
+2  A: 

For small lists, there's no issue with doing this. As you mention, you may want to think about a more 'elegant' solution for large lists (especially lists with unknown sizes).

Sometimes it feels wrong, but it's all right. You'll learn to love break in time.

Daniel May
I don't know.... I've been programming for about 15 years. I do it (use the break), it just seems like cheating sometimes....
ChronoFish
+2  A: 

Like you said ""why not?" It's quick and more importantly easy to understand and follow."

Why feel dirty, I see nothing wrong with this.

Glen
+2  A: 

I think is is easier to read and hence easier to maintain.

Upper Stage
+2  A: 

It is meant to be like it. Break is designed to jump out of a loop. If you have found what you need in a loop why keep the loop going?

Darkerstar
A: 

Perhaps I'm misunderstanding your use-case, but why break at all? I'm assuming you're expecting the test to be true for at most one element in the list?

If there's no performance issue and you want to clean up the code you could always skip the test and the break.

for (object in objectList)
{
  //do some process on object
}

That way if you do need to do the process on more than one element your code won't break (pun intended).

ctford
I would only break cases where I want to find the first (or only) item to match my test clause. Simply letting the loop continue is just burning cycles in these cases.
ChronoFish
It depends on whether you're more concerned about burning brain-cycles or CPU-cycles. Breaking is an optimisation - it might be a justified one but if the list is small then consider leaving it out until you know you need it.
ctford
A: 

My preference is to simply use a break. It's quick and typically doesn't complicate things.

If you use a for, while, or do while loop, you can use a variable to determine whether or not to continue:

for ($i = 0, $c = true; ($i < 10) && $c; $i++) {
    // do stuff

    if ($condition) {
        $c= false;
    }
}

The only way to break from a foreach loop is to break or return.

Jordan Ryan Moore
I do this, though usually only with a `while` loop.
Tenner
So you'd rather add a flag, five lines, and ``?
Tordek
-1 this is no benefit
JonH
It might not be a better solution, but at least it is another approach ;)
Felix Kling
I never claimed that adding another variable was my preference. It's an option.
Jordan Ryan Moore
I'm not sure your answer warranted a down-vote. The only issue I have with what you've written is that it doesn't really allow you to itterate over an associative-array of objects which tends to be when the issue arises.
ChronoFish
+5  A: 

It's quick and more importantly easy to understand and follow.

Don't feel bad about break. Goto is frowned upon because it's quick and more importantly not easy to understand and follow.

Jere
+2  A: 

Breaks and continues are not gotos. They are there for a reason. As soon as you're done with a loop structure, get out of the loop.

Now, what I would avoid is very, very deep nesting (a.k.a. the arrowhead design anti-pattern).

if (someCondition)
{
    for (thing in collection)
    {
        if (someOtherCondition)
        {
            break;
        }
    }
}

If you are going to do a break, then make sure that you've structure your code so that it's only ever one level deep. Use function calls to keep the iteration as shallow as possible.

if (someCondition)
{
    loopThroughCollection(collection);
}

function loopThroughCollection(collection)
{
    for (thing in collection)
    {
        if (someOtherCondition)
        {
            doSomethingToObject(thing);
            break;
        }
    }
}

function doSomethingToObject(thing)
{
    // etc.
}
Jarrett Meyer
Once upon a time when I started out programming I had a really cool nested if-statements for password check .... :)
starcorn
A: 

Use a

Object object;
int index = 0;

do
{
    object = objectList[index];
    index++;
}
while (object.test == false)

if breaking from a for loop makes you feel uneasy.

luvieere
That assumes a numeric index.
ChronoFish
Extend the idea to any kind of index as long as it can be enumerated and there is a way to go from one item to the next.
luvieere
+5  A: 

See, the break doesn't bug me at all. Programming is built on goto, and for-break - like all control structures - is merely a special-purpose form of goto meant to improve the readability of your code. Don't ever feel bad about writing readable code!

Now, I do feel dirty about direct comparisons to true, especially when using the type-converting equality operator... Oh yeah. What you've written - if (object.test == true) - is equivalent to writing if (object.test), but requires more thought. If you really want that comparison to only succeed if object.test is both a boolean value and true, then you'd use the strict equality operator (===)... Otherwise, skip it.

Vagabond
Good point about the "== true" thing. I always want to suggest that people use "if ((object.test == true) == true)", just to see if they get how ridiculous it is.
Paul Tomblin
A: 

In general there is nothing wrong with the break statement. However your code can become a problem if blocks like these appear in different places of your code base. In this case the break statements are code small for duplicated code.

You can easily extract the search into a reusable function:

function findFirst(objectList, test)
{
  for (var key in objectList) {
    var value = objectList[key];
    if (test(value)) return value;
  }
  return null;
}

var first = findFirst(objectList, function(object) {
  return object.test == true;
}
if (first) {
  //do some process on object
}

If you always process the found element in some way you can simplify your code further:

function processFirstMatch(objectList, test, processor) {
  var first = findFirst(objectList, test);
  if (first) processor(first);
}

processFirst(
  objectList,
  function(object) {
    return object.test == true;
  },
  function(object) {
    //do some process on object
  }
}

So you can use the power of the functional features in JavaScript to make your original code much more expressive. As a side effect this will push the break statement out of your regular code base into a helper function.

Fabian Jakobs