Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Just before subroutine returns

by solegaonkar (Beadle)
on Aug 29, 2017 at 05:56 UTC ( [id://1198245]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks! Can you please help me with this problem? I have a complex subroutine in a legacy Perl code. This subroutine has several "return"s in the body, and it is called in hundreds of places in the code. There is some issue in this subroutine and I want to add some logs to mark the end of the subroutine - when the function returns. Is there a way I can hook a code to execute just before the subroutine exits - without having to push something before each return or each invocation of the subroutine? - there are just tooo many of them!! Something like an END block for the subroutine?

Replies are listed 'Best First'.
Re: Just before subroutine returns
by Athanasius (Archbishop) on Aug 29, 2017 at 06:32 UTC

    Hello solegaonkar,

    Try the End module. Here’s a trivial example:

    use strict; use warnings; use End; foo(4); foo(6); sub foo { my ($n) = @_; my $x = end { print "\$n = >$n<\n" }; return 1 if $n < 5; $n *= 52; return $n; }

    Output:

    16:31 >perl 1810_SoPW.pl $n = >4< $n = >312< 16:31 >

    Note that the assignment to $x is needed here, because of the way End works, even though the value of $x isn’t used.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Even the command line to install it is pure fun:

      karls-mac-mini:monks karl$ cpanm End --> Working on End

      Thanks and regards, Karl

      «The Crux of the Biscuit is the Apostrophe»

      perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

      Yes! That worked.. Thanks for your help!

        If you need to know which return returned, you might be able to wrap return using Keyword::Declare or Filter::Simple.

        Be warned: These are very powerful, therefore dangerous to use.

Re: Just before subroutine returns
by haukex (Archbishop) on Aug 29, 2017 at 08:46 UTC
Re: Just before subroutine returns
by TheDamian (Vicar) on Aug 29, 2017 at 14:08 UTC
    Another possibility would be the Scope::Upper module:
    use Scope::Upper 'reap'; foo(4); foo(6); sub foo { my ($n) = @_; reap { print "\$n = >$n<\n" }; # <-- Exec block when sub exits return 1 if $n < 5; $n *= 52; return $n; }
Re: Just before subroutine returns (depends)
by LanX (Saint) on Aug 29, 2017 at 15:49 UTC
    You've got excellent answers, but I think it's important to explain that they fall into different categories.

    The one category shown is basically installing a wrapper with the same name, and execute code before the original sub is entered and after it is exited. This is very stable and easy to achieve without changing the monitored sub, but comes with the drawback that information about internal state- i.e. lexical vars - is lost.

    The other category shown is adding a lexical inside the sub, which holds an object. At the moment the sub (or generally the scope) is left , lexicals without reference count will be destructed and the DESTROY method will be called. This method can trigger a call back which can display the internal state in its closure.

    But I'm not sure that you can know achieve info where - i.e. at which return - the sub is left.

    A third - yet not demonstrated - category is to use the debugger. There you can define watch and trace expressions for subs which will trigger at different points. But this approach comes with dramatically reduced execution speed and won't be appropriate inside a long running process, like e.g. a web application.

    So the appropriate answer depends on the exact nature of the information you (or someone else digging up this thread) wants to gather. :)

    HTH

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

      The fourth category is those of us who are just glad we don't have to read the OP's code. This one sub has so many returns that he can't just put a log statement in front of each of them? Yikes!

        Log statement for each of many returns or log statement for each of many execution branches comes to the same number of log statements if you are trying to determine execution sequence as is implied by OP's question. So there is no "logging" advantage to multiple returns here, and there are vast opportunities to make the flow of code clearer by using early exits.

        Multiply nested conditional code blocks and loops with a single exit: Yikes! (throws up hands and runs away).

        Premature optimization is the root of all job security
        We - or at least me - don't answer for the OP but for the archive.

        There are many possible cases where one needs to monitor subs, like e.g. needing to maintain foreign code and needing to figure out the intended mechanics.

        And PM is not Stack-Overflow, our strength is to have deep discussions not just singular case recipes.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

        Maybe the OP didn't write the code, just inherited it.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-03-28 21:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found