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

This is one of those things that always has bugged me, but never have taken the time to ask. Question, is it acceptable to exit a program/script from a sub routine? Sure, it works, but is it Perlish?

&do_task(); sub do_task { ... do something... if ($somecondition) { exit(); } }

OR

&do_task(); exit(); sub do_task { ... do something... if ($somecondition) { return(); } }

So, is it a better practice to return to the main body to exit, or can I just get out when the gettin' is easiest? TIA

(Yes, I know I don't need the & to call my sub, but it's a helpful visual clue. Comments?)


—Brad
"The important work of moving the world forward does not wait to be done by perfect men." George Eliot

Replies are listed 'Best First'.
Re: Exiting script from subs
by dragonchild (Archbishop) on Apr 15, 2005 at 02:05 UTC
    Generally, if you're exiting within a subroutine, you're doing so for some abnormal reason, so die() is perfectly appropriate. Personally, I would expect to see the second version if the script termination is the standard processing mode.

      Question, as it has come up in this thread twice, and that is the issue of die() vs exit((). The Camel states that one should not exit a subroutine when an error needs to be trapped. But if not, is die necessary, or is exit sufficient?

      Comments?


      —Brad
      "The important work of moving the world forward does not wait to be done by perfect men." George Eliot
        What the Camel does or doesn't say is mostly irrelevant. If your coding standards allow for exit() within a subroutine, then use it. However, most of the community has come to expect die() within subroutines and exit() (if it's even used) from the main scope.

        Now, die() and exit() do different things. The biggest difference is

        eval { print "Inside\n"; die; }; print "Outside\n"; ---- Inside Outside
        vs.
        eval { print "Inside\n"; exit; }; print "Outside\n"; ---- Inside
        exit() exits, end of story. die() allows for some manner of error trapping. This is the main reason why die() is preferred within subroutines. You may want to reuse that subroutine somewhere else that wants to be able to trap the abnormal termination. Also, die() triggers $SIG{DIE}, which can also be useful to trap.

        I would say not, for one thing it limits the possibility of reuse in your code if you are to issue the untrappable exit() in your subroutine.

        /J\

Re: Exiting script from subs
by djp (Hermit) on Apr 15, 2005 at 03:08 UTC
    If you're going to do this, I suggest exit(1) or other non-zero exit status if it's an abnormal termination, this is somewhat like die. exit(0) from deep in the code might raise some eyebrows.
Re: Exiting script from subs
by gellyfish (Monsignor) on Apr 15, 2005 at 08:10 UTC

    Personally I would always prefer to exit the program from within the main program rather than a sub-routine, of course you can't always achieve this due to exception conditions that may occur in the sub-routines (well you could if you were to wrap the whole of the program in a block eval - thus achieving a single point of exit.)

    If nothing else it makes maintenance easier if there is only once logical point of exit from the program and that is easily visible within the main body of the code. This becomes more difficult with event driven programming (such as with a GUI or such-like) but it is still possible.

    We are relatively lucky with languages such as Perl inasmuch as they will clean up all committed resources on program exit - but there have been systems where it was often a fatal mistake to exit the program without closing open filehandles or free allocated memory, but I would still consider it good practice to control the program flow in such a way that you are in a position to release resources where necessary.

    (BTW you nearly got a whole spam e-mail instead of this - I pasted into the comment box rather than the spamcop text area and hit submit before I realised what I had done - more coffee needed.)

    /J\

Re: Exiting script from subs
by DrHyde (Prior) on Apr 15, 2005 at 09:06 UTC
    It's acceptable. I recommend using die() and documenting that this can happen and under exactly what circumstances, so that whoever is re-using your code isn't left scratching their head when it happens. And more importantly, so that they can, by calling your sub in an eval, catch your die and deal with it more gracefully if they need to.

    You'll also want to catch and examine those dies in your tests.

Re: Exiting script from subs
by Tanktalus (Canon) on Apr 15, 2005 at 03:40 UTC

    I don't see any problem with exiting from within a subroutine, no matter how deep, if it makes sense. I do, however, see a problem in using the & sigil when you don't need it. It confuses me into wondering what do_task is, when it's just a normal perl subroutine (as opposed to a reference, or a sub with a prototype (which I would wonder what the prototype was) or ...). The visual clue I use for calling functions is the parentheses. The & is only there when it needs to be - it's a good visual clue that something abnormal is going on.

Re: Exiting script from subs
by dmorelli (Scribe) on Apr 15, 2005 at 02:32 UTC
    I think it may also depend on the scope of the script. Something quick and small, sure, why not. Like writing one-liners without strict or warnings.

    I could definitely see exiting from just any old sub being a problem in larger projects.

Re: Exiting script from subs
by Trix606 (Monk) on Apr 15, 2005 at 13:56 UTC
    I tend to think of subs as something you are going to return back from unless there was a grievous error. The only exception would be a specificly named termination()or some such sub that might be used to consolidate end-of-program tasks. As programs grow in size exiting from a sub sets up a trap that is too easy to fall into.
Re: Exiting script from subs
by graq (Curate) on Apr 15, 2005 at 16:34 UTC
    I would personally not want to hide an exit statement inside a block like that.
    It strikes me that what you want is for the program to end (as opposed to abend) based on certain criteria.
    This makes it look a little like this:
    my $result = do_task(); exit() if ($result eq 'exit'); sub do_task { ... do something... if ($somecondition) { return 'exit'; } }
    Obviously the string 'exit' is not that desirable (and for the sake of your example), but the return code should depend on what the function does (and allow for further scope).
Re: Exiting script from subs
by UlkeshNaranek (Initiate) on Apr 15, 2005 at 21:33 UTC
    Personally, I prefer to use exit() myself. Most of my work tends to be on web applications, and when you're dealing with the world at large, I've found they don't always do what you want them to. So I usually have a specific termination function in most scripts, the goal of which is to make sure all things are closed down that should be, and to NICELY give the end user an information page on why they shouldn't have done what they did. (Most people whose code I've seen that are fond of die() leave the user with a single line of text in an empty window - often with an error message that they don't understand). But that's just me, and web programming. :-)
Re: Exiting script from subs
by gam3 (Curate) on Apr 15, 2005 at 15:09 UTC
      You know, that article is WAY overused. Remember that it came from a time when people were using line-numbered gotos and creating contstructs (loops) from gotos. My personal (and somewhat informed) opinion is that sometimes a labeled goto can simplify a loop exit in such a manner that one line could replace many conditionals. In the case where a goto replaces multiple conditionals inside a loop, this not only makes the code more readable but it can also make the code run exponentially faster (conditionals take clock cycles). The article you referenced is about people abusing the goto and the need for more friendly/readable constructs that would help make more maintainable code. If the occasional goto helps move more to that end, then use it.

        Exponentially faster? Only if your code isn't actually doing anything other than test exit conditions inside that loop, I'd think. The maintainability benefit, on the other hand, is gigantic, though I'd use Perl's last LABEL; construct (with a label on the outer loop) rather than a literal goto (I personally find this a much tidier mechanism, though I realize that they're fundamentally pretty much equivalent).

        And not, of course, that I would disagree with the statement that both that article headline in particular (usually without the link) and "$foo considered harmful" in general are employed in many places where they probably shouldn't be—just wanted to throw in some minor quibbles on the specifics.



        If God had meant us to fly, he would *never* have given us the railroads.
            --Michael Flanders

Re: Exiting script from subs
by FuBaR (Acolyte) on Apr 15, 2005 at 23:27 UTC
    For me I try to never exit in a sub unless I am forced to. But that's just my preference. It is one thing to exit in a sub in a small script or program where it is easy to spot.
    If on the other hand you are working on a large project with several programmers that can be a nightmare, and as stated above that can also kill some reusability.
    For me I would rather pass back an exit code or something and bail out from main().

    Thats my 2 cents....keep the change.
Re: Exiting script from subs
by Mabooka-Mabooka (Sexton) on Apr 17, 2005 at 20:30 UTC
    The Art of UNIX says: "Repair what you can — but when you must fail, fail noisily and as soon as possible".