4

I was reading on this page about setting a flag in a loop and using it later. Most of the answers agreed that it's a code smell.

One of the answers suggested refactoring the code by putting the loop into a method and the boolean and break become a return instead.

The second answer suggests that using the break means your loop has two possible exit points, and if your code becomes more complex, it might be harder to detect and introduce bugs.

Question:

By the logic of the second answer isn't using a return statement also a code smell? Using a return you introduce a second way to exit the loop.

marked as duplicate by gnat, amon, Christophe, Robert Harvey, Kilian Foth Jan 24 '18 at 7:17

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

1

setting a flag in a loop and using it later

... is called the dirty flag or dirty bit pattern. It is perfectly possible to do this without it being a code smell.

Multiple returns are a code smell in languages like c where having one exit point provides one place to clean up used resources. Using break here can help. It's worth considering this even when their are no used resources here because some day I may have to add some and I'd appreciate it if you didn't force me to redo tons of code.

However, if you're in a language that has finally blocks you can use more than one return freely because I can easily add a finally block later. Early returns can make the code more readable. A popular style is to deal with special cases 1st and put the more typical case at the end.

Baring any other problems dirty flag and multiple return can work and often switching between them is just a micro optimization that wouldn't provide a big O improvement. Choose what makes the code most readable.

Code smells are nothing but the start of looking into improving the code. No book or blog post knows your real situation better then you and you team.

3

From my point of view, if the method/function is long or complex enough to make an additional exit point confusing, then the smell is probably the length/complexity, not the return itself. Take for instance exceptions: they are (exceptional) exit points as well, but nobody would defer them until later.

My personal preference is to exit the routine as soon as it's done and has a final result available. That lets me focus only on "the other path" from that point on. Otherwise, I'd have rather long and deeply nested "elses" just to cover those paths.

But then this is very relative. It depends on how readable is the language, the function/method, and even other factors such as cleaning up (as mentioned by CandiedOrange in their reply). I just happen to see as more important the overall method clarity and simplicity over the multiple exit points.

0

YES! traditionally More than one return from a function is a code smell.

Nowadays there are widely used practices that are common enough to be recognised as an exception to the rule

  • early return guard clauses
  • exceptions

However, I believe the (highly underrated) second answer is really talking about the combination of the second exit point and the setting of the flag.

The combination requires the early exit AND further checking of the variable after the loop completes.

For instance a loop with a return when a condition is met

foreach(var x in list)
{
    if(condition(x)) { break;}
    //whatever
}
return z;

Is fairly obvious and a simple optimisation.

But a loop which sets variables AND has multiple returns quickly becomes non obvious and potentially buggy

var z
foreach(var x in list)
{
    if(condition(x)) { z = something }
    if(condition2(x)) { break;}
}
if(z==something)
{
    //will this code execute?
}
return z;

Analogous to a function with side effects, or a global variable.

The same is true for multiple returns

//some code
if(condition)
{
    return x
}
//more code possibly not executed
if(condition2)
{
    return y
}

//more code possibly not executed
return z;

OR

foreach(x in list)
{
    if(condition)
    {
        flag = y;
    }
    if(condition2 && flag)
    {
        return b;
    }
    if(condition3)
    {
        return c;
    }
}

Scanning the code you cant tell which return will be hit. But you can see that there is more than one exit. This is the "code smell" which tells you you need to look more closely at this function as it could do something unexpected.

Because we are "triggered" by this code smell its best to avoid it, even in the simple cases by simplifying to a while loop or map, to remove the second return/break

while(x.next && !condition(x))
{
    //whatever
}

list.Where(x=>condition(x)).select(//whatever)

When we scan this code we know that it can only do a single thing because there is only a single exit point. To get past it the conditions stated at the start must have been met. We might not care how, all we know is we can continue reading the code knowing what the state of the variables must be.

  • "(highly underrated) second answer" -- are you referring to your answer? If yes why don't you mention it – gnat Jan 23 '18 at 22:08
  • I can see this one will follow the pattern – Ewan Jan 23 '18 at 22:09
  • 1
    do you mean a guard clause to avoid an exception? I think I've covered that above. Although personally I would try avoid it even there. After all you probably want to show a validation message or something rather than exit – Ewan Jan 23 '18 at 23:15
-4

“Code smell” means that someone highly opiniated looked at the code superficially, and decided that it “smells”, without actually looking closer. Usually that opinion itself stinks.

The code you refer to was absolutely fine (apart from some minor issues that had nothing to do with the question).

Write code that expresses clearly what it should do, keep it simple, and don’t worry about someone screaming “code smell”.

  • Judging from the downvotes, I guess people really like smelling code. – Robert Harvey Jan 23 '18 at 21:31
  • 5
    That's not what code smell means. Code smells are "just cause" to take a deeper look and see if something can be improved, not a final declaration that the code is terrible based on superficial criteria. – Karl Bielefeldt Jan 23 '18 at 21:43