http://qs321.pair.com?node_id=686266

weedom has asked for the wisdom of the Perl Monks concerning the following question:

I'm currently reviewing someone elses code, and have come across this little gem
foreach my $enum( @$enums) { return 1 if ( $check_type eq $enum); }

now, I want to throw this back for a little bit more work, cos it just looks wrong. I don't like the fact that it just leaves the loop hanging in mid-air.

But I need a wee bit more ammo than simply "I don't like it". Is there anything actually "bad" about doing this? Or am I just being fussy?
UPDATE: Wow! I expected a lot more support for my way of thinking - I stand corrected, and will now go back and eat humble pie.

Thanks, Monks. Anonymous Monk, I shall pass your code on to my reviewee. :)

Replies are listed 'Best First'.
Re: "return" to break out of a loop
by moritz (Cardinal) on May 13, 2008 at 14:25 UTC
    IMHO there's nothing wrong with it.

    Some languages (like Eiffel) disallow such a construct to make it easier to prove the correctness, and to get a better idea about the flow of the program (which is in this case: it runs through the method until it hits the end of that method).

    But I found return and last useful at times, and wouldn't want to miss it.

      For this to _really_ be nice, stuff like if would have to return the last value of the executed block:
      sub is_even { if (shift % 2) { 0 } else { 1 } }
      We already have the ternary operator, but I find it can get hard to maintain when used often in one statement. Sparkling some do { .. }'s in only makes it a bit better.

      Ordinary morality is for ordinary people. -- Aleister Crowley
Re: "return" to break out of a loop
by ikegami (Patriarch) on May 13, 2008 at 14:30 UTC
    sub foo { for (...) { return 1 if ...; } return 0; }
    is actually a rather common construct. If you don't like it, you could use a flag variable.
    sub foo { my $found = 0; for (...) { if (...) { $found = 1; last; } } return $found; }
    You could even get rid of the last by changing the loop control. But everytime you change something from the original, it gets bigger and more complex, and therefore harder to read and more error prone.
Re: "return" to break out of a loop
by Joost (Canon) on May 13, 2008 at 14:37 UTC
    I use this kind of stuff quite a bit. Of course it can get confusing if your subs are large, but subs should not be large anyway.

    Also compare the relatively simple

    sub direct_return { my ($enum,$check_type,$enums) = @_; foreach my $enum (@$enums) { return 1 if ( $check_type eq $enum); } return; }
    to the mess you get when you start to believe that there should be only one return in a sub:
    sub otherwise { my ($enum,$check_type,$enums) = @_; my $flag = 0; LOOP: foreach my $enum (@$enums) { if ( $check_type eq $enum) { $flag = 1; last LOOP; # not really needed unless you've got nested loops } } return $flag ? $flag : wantarray ? () : undef; }
Re: "return" to break out of a loop (super)
by tye (Sage) on May 13, 2008 at 15:02 UTC

    Not to "pile on", but I wanted to note that over the years I've found "early return" to be one of the best refactoring tools. I've used it to turn many a convoluted loops with overly complex flow control into a "trivial" / "obvious" loop that calls a very simple subroutine with an early return. It is the most maintainable of "jump out here" flows, quite a bit better than last or my $done= 0; and tons better than "bare block as 'loop' with redo" [expletive], for example.

    - tye        

Re: "return" to break out of a loop
by jettero (Monsignor) on May 13, 2008 at 14:29 UTC
    There's nothing wrong with it. It's not only common practice, but it's an efficient way to break out of a loop and return a value (shortcutting the rest of the function logic). It's probably correct. I suppose there are places where it's bad to do it, but nothing comes to mind.

    -Paul

Re: "return" to break out of a loop
by 5mi11er (Deacon) on May 13, 2008 at 14:40 UTC
    Yes, you're being overly fussy. This type of construct is very common because it is both clear and more efficient than say setting a "truth flag" then having to finish examining the rest of the values.

    The other way to write this and to keep efficiency is something like:

    my($flag)=0; foreach my $enum( @$enums) { if ( $check_type eq $enum) { $flag = 1; last; } } return $flag;
    Which is about twice as long. So, I personally like the 4 line version better.

    -Scott

    Update: I like anonymous monk's one line grep version above even more :-)

Re: "return" to break out of a loop
by dragonchild (Archbishop) on May 13, 2008 at 15:04 UTC
    I think the key here is that you want to come to a decision as quickly as possible. In other words, "Fail quickly, for that is the only path to sucess."

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: "return" to break out of a loop
by psini (Deacon) on May 13, 2008 at 14:27 UTC

    I don't think there is anything actually bad in exiting from within a loop but...

    ...I too don't like it :)

    I think of it as inelegant. My personal feeling is that a sub should end at or near the end of its block, but again perhaps I'm just beeing fussy.

    Rule One: Do not act incautiously when confronting a little bald wrinkly smiling man.
Re: "return" to break out of a loop
by Anonymous Monk on May 13, 2008 at 14:33 UTC
    Hanging loop? In mid-air?
    return 1 if grep { $check_type eq $_ } @$enums;
      Very short but not very efficient because the implicit loop is not aborted at the first successful match. Because grep is returning the number of successful matches in scalar context all list elements are getting checked.
      More efficient would be:
      use List::MoreUtils; return 1 if any { $check_type eq $_ } @$enums;
      meh. Figure of speech :) Cheers WeeDom
Re: "return" to break out of a loop
by GrandFather (Saint) on May 13, 2008 at 21:23 UTC

    Early exits in various guises are a powerful tool in making program flow clear and maintainable. They are very good tools for avoiding levels of nesting and thus the obfuscation of program flow and context that levels of nesting engender.

    A related style issue to consider is instead of:

    for ... { if ... { ... } else { ... } }

    use

    for ... { if ... { ... next; } ... }

    especially where the true path is a trivial case, or can be made into a trivial (small number of lines of code) case such as an empty line to be skipped or an error condition.

    In other words, deal with the trivia and fluff first and early exit where possible to avoid levels of indentation.


    Perl is environmentally friendly - it saves trees
Re: "return" to break out of a loop
by FunkyMonk (Chancellor) on May 13, 2008 at 22:26 UTC
    Back in the dark ages, when I was was at uni, I was taught that every programming construct should have exactly one entry and exactly one exit point1

    It sucked then, and it still sucks now. return inside a loop is perfectly acceptable.

    --
    1Anyone else remember Jackson Structured Programming?


    Unless I state otherwise, all my code runs with strict and warnings

      Oh, do I remember! With the same relish as I remember being beaned in the head with a chalkboard eraser by my teacher for talking in class in 3rd Grade or of being paddled in the principal's office for getting into a fight on the playground in 4th Grade. Yeh, I remember.

      ack Albuquerque, NM
Re: "return" to break out of a loop
by weedom (Acolyte) on May 13, 2008 at 14:49 UTC
    As per my update... thanks, all. I have been guilty of excessive hubris (I think. Could be pride, or pedantry), and shall carry out a penance of some sort.

    WeeDom

      I think a spanking is in order.