in reply to goto &sub and local question

My understanding of goto &s1 is that control is transfered to the subroutine s1 without any change in the stack.

Read the docs!

it exits the current subroutine (losing any changes set by local()) and immediately calls in its place the named subroutine using the current value of @_.

"No changes to @_" is not "no changes to the stack". Quite the opposite, the goal of goto &name is to remove the current stack frame.

You want just &name;, not goto &name;. It preserves @_ without removing the current stack frame.

sub s1 { our $var; print "arg: $_[0]\n"; print "local: $var\n"; } sub s0 { local our $var = 'local'; &s1; } s0('arg');
arg: arg local: local

Update: Initially, I accidentally left out the bit about &name;. Added.

Replies are listed 'Best First'.
Re^2: goto &sub and local question
by rovf (Priest) on Nov 24, 2008 at 09:33 UTC
    You want just &name;, not goto &name;.

    Thanks a lot for the clarification. Unfortunately, in my particular application I think I need the 'goto' form, but I can solve the problem by using just usual package global variables. It's not a nice solution, but it affects only a few closely coupled subroutines, so I don't think I will run into maintenance problems.

    -- 
    Ronald Fischer <ynnor@mm.st>

      "Unfortunately, in my particular application I think I need the 'goto' form ..."

      Why? What about your usage requires you to call a subroutine with goto? After all, "the author of Perl has never felt the need to use this form of goto."

      Also, you mention that your solution is to affect a few closely coupled subroutines with global variables. I can't help but associate the word closely with the word tightly -- which is exactly how subroutines are not supposed to be coupled. Loose coupling and tight cohesion is the goal. I can't help but think that maintenance problems are all that you are adding and that there is a better solution for you, but it is difficult to know for sure without seeing more of your code.

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
        After all, "the author of Perl has never felt the need to use this form of goto."
        Ah, the perils of quoting out of context. Your quote is actually talking about the C-style "goto label", not to the tail-call goto under discussion in this thread.
        Why? What about your usage requires you to call a subroutine with goto?

        Well, I wanted to spare you these tedious details, because I didn't consider them important to know, but here we go:

        The module these functions are in is a mediation layer to a logging module (Log::Log4perl actually). Originally, the client modules used, for instance, Log4perl functions such as DEBUG(...) or ERROR(...) to generate the logs.

        This system is now about to be modified in that DEBUG, ERROR etc. should first invoke some of our own code to do some preliminary work, and then pass on the DEBUG, ERROR etc. of the Log4perl module. In addition, my own version of these routines to do first some special processing, then some general processing (which is common to all type of traces), and then pass control to Log4perl. Basically, the information flow is as follows:

        1. User calls DEBUG(), ERROR(), INFO() etc., invoking my own DEBUG/ERROR/INFO routines.
        2. My DEBUG does some actions specific to the debug case.
        3. Next, the general code (common for DEBUG, ERROR etc.) is executed.
        4. Finally, Log::Log4perl::DEBUG/ERROR/INFO etc. is run
        If I would do this with normal function calls, i.e.
        package MyLogging; ... sub DEBUG { ... general(\Log::Log4perl::DEBUG,@_); } sub general { my $logger=shift; ... &$logger(@_); }
        the Log4perl logging routines would report MyLogging::general as caller, instead of the original call site of DEBUG().

        Maybe there is a callback mechanism in Log4perl which I could use; the documentation of Log4perl is pretty big and I thought that my problem is so easy that I could do it simply by using (kind of):

        package MyLogging; ... sub DEBUG { ... unshift @_,\Log::Log4perl::DEBUG; goto &general; } sub general { my $logger=shift; ... goto &$logger; }

        Actually, it *does* work that way, and I believe that since these functions are small and co-operate closely, it is also easy to understand. Still, I am not absolutely happy with the solution either. If I find time, I should maybe take a few hours to wade through the Log4perl docs to get ideas for other solutions.

        -- 
        Ronald Fischer <ynnor@mm.st>