Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

strange code (de)referencing behavior

by dsb (Chaplain)
on Feb 10, 2012 at 15:23 UTC ( [id://953043]=perlquestion: print w/replies, xml ) Need Help??

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

Hello all,
I've got some behavior I think is a bit odd, and I'm guessing it's just b/c of the way perl handles things internally, but I'm curious as to how/why this is happening.

I have a function being called by a code ref stored in a hash of code refs. The function is passed on the command line, and then by a series of conditions, is called from a class method of package Util.pm like so:

sub dispatch { my ($self, $fname) = @_; &{$dispatchTable{$fname}}; ## note, no arguments }
Where $fname is the name of a function parse() in a seperate package, Parse.pm.

In Parse.pm, parse()'s first few lines are

sub parseAutorep { my $isCombined = shift;
$isCombined is a variable meant to give the user the option to string a series of functions together into a collective check rather than run each individually. In this case, with parse() seeming called with no arguments, I expected $isCombined to be undefined.

However, it's getting set with the Util.pm object that contains the dispatch() method that is calling parse().

it almost seems like, behind the scenes, the full call looks like:

Util::dispatchTable->Parse::parse();
or something like that.

UPDATE: It actually looks like parse() is getting the same argument list that was passed to the function that called it, dispatch(), if that sheds any light for anyone.

Anyone have any insight? At this point, the simple answer is to just shift the object out of the way...no biggie. But I'm really just curious about what's happening here.


dsb
This @ISA my( $cool ) %SIG

Replies are listed 'Best First'.
Re: strange code (de)referencing behavior
by choroba (Cardinal) on Feb 10, 2012 at 15:37 UTC
    Calling a subroutine this way
    &{...}
    forwards the @_ arguments. (Try sub f { say while $_ = shift; warn "Called\n" } %d = (1 => \&f); sub g { &{$d{1}} }; g(1, 2).) If you want to avoid that, use -> for dereference:
    $dispatchTable{$fname}->();

      Although I do prefer the arrow notation, the minimal change solution is actually

      &{$dispatchTable{$fname}}()
Re: strange code (de)referencing behavior
by kennethk (Abbot) on Feb 10, 2012 at 15:54 UTC
    If you modify your code to output the content of the incoming argument array,
    sub parseAutorep { print join "\n", map defined ? "'$_'" : '<undef>', @_; }

    your output will be

    'Util' 'parse'
    This is because (as documented in perlsub):
    If a subroutine is called using the & form, the argument list is optional, and if omitted, no @_ array is set up for the subroutine: the @_ array at the time of the call is visible to subroutine instead. This is an efficiency mechanism that new users may wish to avoid.
    The solution is to include parentheses in your call if you really want a null argument list. Alternatively, if you'd like the option of passing additional arguments, you could just shift both the package and subroutine name off the argument stack:
    sub dispatch { my ($self, $fname) = (shift,shift); &{$dispatchTable{$fname}}; }
Re: strange code (de)referencing behavior
by Anonymous Monk on Feb 10, 2012 at 15:52 UTC
    $ perl -le " $f = sub { warn @_; }; sub f { &{$f}; } f(6,6,6); " 666 at -e line 1. $ perl -le " $f = sub { warn @_; }; sub f { $f->(); } f(6,6,6); " Warning: something's wrong at -e line 1.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (6)
As of 2024-04-18 07:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found