Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Entering and exiting subs in style

by bradcathey (Prior)
on May 26, 2004 at 02:51 UTC ( [id://356440]=perlquestion: print w/replies, xml ) Need Help??

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

I have a question about getting in and out of subs nicely, especially when calls/returns to subs get numerous or complicated. I'm not sure if it's a question of style or function.

A couple of scenarios. In #1 I don't really wish to return to &foo if the condition in &bar is negative. Is just exiting an okay move?
#--------- 1 ------------ sub foo { &bar; } sub bar { if ($negative) { exit(); } return(); }
or, for the sake or purity, do I need to return to &foo and then return out of &foo?
And next, what might be an obvious question, what is the difference between the typical call to &bar in #1 and the addition of 'goto' in #2?
#--------- 2 ------------ sub foo { goto &bar; }
or is goto for recursive calls only (as discussed here) or just plain redundant? The goto discussion appears to be saying that using goto to get into a subroutine is not recommended.

Thanks!

—Brad
"A little yeast leavens the whole dough."

Replies are listed 'Best First'.
Re: Entering and exiting subs in style
by chromatic (Archbishop) on May 26, 2004 at 03:04 UTC

    In your first scenario, it's okay to call exit (that's what it's for!), as long as you document that the subroutine could exit under specific circumstances.

    In the second scenario, the goto actually replaces the current entry on the call stack. If you don't know what this means or why you'd want to do it, you probably don't need to use this form.

    As a side note, I much prefer calling bar() instead of &bar. Again, if you don't know the difference or why you'd want to do it, you're probably much better off with the parenthesis.

      As stated above, goto replaces the current call on the stack... In your code, I think it might be useful:

      use strict; sub foo { goto &bar if ( $_[0] < 0 ); return "$_[0] from foo\n"; } sub bar { return "$_[0] from bar\n"; } print foo(-1);

      If you run this code, you'll get -1 from bar\n as your output. Put simply, goto will replace the current call to &foo with a call to &bar. There are several limitations to this method, though... You can't pass &bar any parameters; &bar will be passed the arguments which &foo was called with. That being said, the second limitation is that you don't mess around with @_ in the calling subroutine... you'll surely regret it later. For further information, see pages 127 and 297 of The Bible.
Re: Entering and exiting subs in style
by graff (Chancellor) on May 26, 2004 at 04:07 UTC
    Regarding #1, there are bound to be occasions where a sub may encounter a condition that really must bring the whole process to a halt. In such cases, "die" (or "croak") would be more appropriate than "exit".

    But even when such a condition might arise, you should choose consciously between dying within the sub vs. returning an error status to the caller. The former choice is typical of one-shot (or "application-specific") code -- the functionality of the sub is so tightly bound to the specific script/app that you wrote it for, it's okay for the sub to exercise this level of control over the entire app.

    On the other hand, if you're writing a sub because it's likely to be useful in a number of different situations, you'll probably be better off having it return to the caller in all cases -- some day you'll want the flexibility of letting the caller decide what to do when the sub hits a given problem. (Then again, if you know the sub will die under certain conditions, the caller can wrap the sub in an "eval" to trap these conditions -- this is also a perfectly legitimate design choice, so long as you document it.)

    As for #2, there are obviously some rarified situations where the magical trappings of goto &some_sub are needed (or at least very convenient) -- otherwise it wouldn't have been added to the language. But I find it hard to imagine situations like that arising in day-to-day application development (which is where I spend most of my programming time). If you're mucking with perl internals (e.g. replacing/enhancing core functions in some subtle, intricate way), or just trying to deepen you obfu skills, sure, it will be handy. But most of the time, there probably isn't any really good reason to use it.

      Thanks, monks, for the thorough replies--very helpful. One thing I heard was "die" vs "exit." I have always associated "die" with errors related to internal operations, such as file handling, etc. So, I checked with perldocs on the issue of exit and found this concurring advice:
      Don't use exit to abort a subroutine if there's any chance that someone might want to trap whatever error happened. Use die instead, which can be trapped by an eval.
      So, better to "die" than just "exit." Sounds a bit too final ;^) but I'll defer to this advice.

      —Brad
      "A little yeast leavens the whole dough."
Re: Entering and exiting subs in style
by edoc (Chaplain) on May 26, 2004 at 03:20 UTC

    I'd say you want to do some (which could easily become "LOTS of") reading up on exception handling which basically involves calling 'die' in one form or another and then catching it further up your code tree. This is a fairly large subject matter so I'll just refer you to some existing threads.. 8) ..exception handling.

    Greatly simplified, untested code..

    #--------- 1 ------------ eval { foo() }; if ($@){ # Houston, we have a problem my $error = $@; } else { # everythings ok. } sub foo { &bar; } sub bar { if ($negative) { die('bar is negative'); } return(); }

    cheers,

    J

Re: Entering and exiting subs in style
by Jasper (Chaplain) on May 26, 2004 at 08:18 UTC
    That goto discussion seems to be saying that goto a subroutine ought only to be used in the most magical circumstances.

    Surely it would render your code completely unreadable, anyway. The return from the sub would take you where? It's not immediately obvious to me, so I wouldn't use it.

    I've only ever used goto once in perl, I forget what my reasoning was, but very shortly after I substituted it for something else (better?).

      That goto discussion seems to be saying that goto a subroutine ought only to be used in the most magical circumstances.
      More to the point is to consider exactly when you would need to use it, and when you care. The circumstances are when you want to fake "caller" to the sub being called, i.e. make your current subroutine invisible.

      One circumstance when you would do this is in an AUTOLOAD subroutine that is generating new subroutines on the hoof (or loading them in from files). Suppose we have a package Foo and function bar, which does not exist at the start of the program. The first call to Foo::bar results in a call to Foo::AUTOLOAD, with $Foo::AUTOLOAD set to 'Foo::bar'.

      The AUTOLOAD code creates a new subroutine and puts it into package name space as Foo::bar, so future calls to Foo::bar call this sub directly. We want the first call to Foo::bar not to see its caller as Foo::AUTOLOAD, but as the real caller. In order to achieve this, AUTOLOAD does a goto &Foo::bar once it has finished.

      Other times when you might need to fake "caller" are more arcane, such as what Hook::LexWrap does internally. You also need to use these techniques if you are writing a debugger, profiler or such like.

      Hopefully this has explained the "magic" in this case.

      --
      I'm Not Just Another Perl Hacker

      I've used goto &sub in some state-machines, just because I didn't want the overhead of creating a larger stack that I'm not intending to use anyway.

      This means that you go from one sub to the other without being able to return back to the first sub - if you return, you go back to the "original caller", which in this case was exactly what I wanted, and it can save some memory that otherwise is being used to store the lexicals in the stack of subs.(AFAIK this is related to tail recursion).

      As far as the OP is concerned, I'd recommend using die, as suggested above.

Re: Entering and exiting subs in style
by pg (Canon) on May 27, 2004 at 01:16 UTC

    You should never call exit from more than one place in your code. If you do, that would become a maintenance nightmare to other people, who might support your code.

    More importantly, there is absolutely no logical need for this kind of style, as your code should always be coded in a way decent enough to handle all exceptions, and properly return from subs accordingly.

    If your code does not do that, then fix it, not to tolerate it.

    Indeed, this breaks modulization, as now other modules are performing functionality (in this case, exit function) that should only be performed by your main module.

    Purity is not a kind of requirement, but a kind of belief.

      Why is using return() inadequate? I think I missed that part. Is it a matter of style and personal preference? I usually use return in all cases, and use returned values to distinguish a "die" situation from a successful return. Part of the reason is that I sometimes need to give the program a chance to "put away its crayons", so to speak. I realize, of course, that there's more than one way to do it. I just want to ask whether I'm missing out by doing it in my old-fashioned way.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://356440]
Approved by graff
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2024-04-20 06:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found