Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Tweaking 'return'.

by eff_i_g (Curate)
on Nov 22, 2005 at 21:40 UTC ( #510923=perlquestion: print w/ replies, xml ) Need Help??
eff_i_g has asked for the wisdom of the Perl Monks concerning the following question:

Monkly Mentors,

I am logging the start and end of subroutine calls for easier debugging. I am doing this by manually placing a function at the start and end, like so: log_line('Begin (or End) call: sub_name');

This is great; however, I am starting to use return's within the routine and I have to repeat the above code before each return.

Is there some Perlish way to tell 'return' to call a function and then do its thing?

Thank You.

Comment on Tweaking 'return'.
Re: Tweaking 'return'.
by ikegami (Pope) on Nov 22, 2005 at 21:48 UTC

    I can't remember what it's called, but there's a module that wraps a function call with pre and post handlers. Sounds perfect if you want to do this for a few functions.

    Update: I found Hook::PrePostCall, but I think there's another one. I haven't used either.

      ...but I think there's another one...

      There is Hook::LexWrap:

      use Hook::LexWrap; wrap( $_, pre => sub { print "$_ begin\n" }, post => sub { print "$_ end\n" }, ) for @subs_to_wrap;

      Updated example to be more inline with OP's requirements.

      ... I think there's another one.

      There's also Hook::WrapSub:

      use Hook::WrapSub qw( wrap_subs ); wrap_subs( sub { print "before $Hook::WrapSub::name (@_)\n" }, @subs_to_wrap, sub { print "after $Hook::WrapSub::name (@Hook::WrapSub::result)\n" +} );
      We're building the house of the future together.
Re: Tweaking 'return'.
by ChemBoy (Priest) on Nov 22, 2005 at 21:53 UTC

    It's conceivable that you could (though I'm somewhat doubtful), but it might be easier, if this is for debugging, to wrap your subroutines, roughly thus (largely untested):

    sub dosomething {print "in dosomething\n" } sub wrappit { no strict 'refs'; my ($subname) = @_; my $oldsub = \&{$subname}; *{$subname} = sub { print "entering $subname\n"; my @rv = wantarray ? $oldsub->(@_) : scalar $oldsub->(@_); print "leaving $subname\n"; return wantarray ? @rv : $rv[0]; }; } wrappit('dosomething'); dosomething(1..5);

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

Re: Tweaking 'return'.
by ptum (Priest) on Nov 22, 2005 at 21:53 UTC
    I think it is called Sub-Versive --

    No good deed goes unpunished. -- (attributed to) Oscar Wilde
Re: Tweaking 'return'.
by traveler (Parson) on Nov 22, 2005 at 22:36 UTC
    This kind of behavor is a feature of "Aspect Oriented Programming" or AOP for short. Check out Aspect for one approach to AOP in perl.

    HTH, --traveler

Re: Tweaking 'return'.
by sgifford (Prior) on Nov 23, 2005 at 03:00 UTC
    I think what you really want to know is when the sub starts, and when it finishes, regardless of whether it finishes because it falls off the end of the sub, returns, or dies. Serendipitously, those are exactly the times when a sub-scoped lexical variable goes out of scope. If you create an object when the sub starts and hold it in a lexical variable, you can print the Entering message in its constructor, and the Exiting message in its destructor. Here's a short example:
    #!/usr/bin/perl use warnings; use strict; package SubLog; sub new { my $class = shift; my $self = { name => (caller(1))[3], }; warn "ENTERING SUB: $self->{name}\n"; bless $self, $class; } sub DESTROY { my $self = shift; warn "EXITED SUB: $self->{name}\n"; } package main; sub blahblah { my $sublog = SubLog->new; return 5; } sub blahsub { my $sublog = SubLog->new; blahblah(); return 3; } blahsub();
      Thanks sgifford, this is just what I needed. I also pulled the line from caller to make things more exact. :)
Re: Tweaking 'return'.
by spiritway (Vicar) on Nov 23, 2005 at 05:09 UTC

    You might consider using only a single return, and directing your flow to it. If you are returning values, then set a variable to the appropriate value in your conditionals, and return from the same point (with the print subroutine just before). If you're only returning based on conditionals, consider setting a flag.

Re: Tweaking 'return'.
by robin (Chaplain) on Nov 23, 2005 at 12:05 UTC
    If you want to track entry and exit to all subroutines, the easiest way is to write a custom debugger. It's actually very easy:
    # This is the custom debugger: { package DB; sub DB {} sub sub { print STDERR "== Entering sub $sub\n"; &$sub; # Call the sub print STDERR "=== Leaving sub $sub\n"; } } # Now some example code to test it with: sub hello { print "Hello, "; world(); } sub world { print "World!\n"; } $|++; # Turn off buffering, to make the control flow clearer hello();
    The debugging code will only be activated if you run with perl -d, so:
    $ perl Hello, World! $ perl -d Loading DB routines from version 1.28 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. == Entering sub main::hello Hello, == Entering sub main::world World! === Leaving sub main::world === Leaving sub main::hello
    See perldebguts for all the gory details.

    Update: As a (probably better) alternative to running perl -d, you can use

    BEGIN {$^P = 1}
    to enable subroutine-tracing. That way you don't need the empty sub DB either. But woe betide you if you should actually run with perl -d. Maybe it's best to use something like
    BEGIN { return if $^P; # If the debugger is running, leave well alone $^P = 1; # Enable subroutine tracing package DB; *sub = sub { print STDERR "== Entering sub $sub\n"; &$sub; print STDERR "=== Leaving sub $sub\n"; }; }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://510923]
Approved by GrandFather
Front-paged by aufflick
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2014-11-28 04:26 GMT
Find Nodes?
    Voting Booth?

    My preferred Perl binaries come from:

    Results (193 votes), past polls