Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Dynamically constructed function calls

by WalruZ (Initiate)
on Nov 03, 2004 at 23:35 UTC ( #405048=perlquestion: print w/ replies, xml ) Need Help??
WalruZ has asked for the wisdom of the Perl Monks concerning the following question:

I'm stupid.

I'm trying to dynamically construct a call to an autoloaded function of a class. The class isn't in my control. I can't come up with the right syntax for the line below the comment in the supplied non-functional example. It looks like it does because I have been flailing.

#!/usr/bin/perl use strict; my %vars = ( 'user_login' => { req => 1 }, 'user_passwd' => { req => 1 }, 'user_display' => { req => 0 }, ); my $f = Foo->new(); while ( (my ($key,$atr)) = (each %vars)) { print "$key, $atr\n"; # eg, trying to construct and call autoloaded # $f->prefix_user_login method. &$f->"prefix_$key"( $atr); } package Foo; sub new { return bless( { }, shift); } sub AUTOLOAD { use vars '$AUTOLOAD'; print "autoloaded method: $AUTOLOAD \n"; } sub DESTROY {}
I genuflect.

Comment on Dynamically constructed function calls
Download Code
Re: Dynamically constructed function calls
by tall_man (Parson) on Nov 03, 2004 at 23:46 UTC
    An eval would do it, like this:
    eval "\$f\-\>prefix_$key\( \$atr\)";
      No. Do not resort to eval-string if other means are available. You're firing up the compiler (slower than almost any other solution), and exposing yourself to hard to debug and hard to secure practices.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

Re: Dynamically constructed function calls
by ikegami (Pope) on Nov 03, 2004 at 23:50 UTC

    There's no need for eval here.

    my $method = "prefix_$key"; $f->$method($atr);
Re: Dynamically constructed function calls
by itub (Priest) on Nov 03, 2004 at 23:53 UTC
    From perldoc perlop
    Otherwise, the right side is a method name or a simple scalar variable containing either the method name or a subroutine reference, and the left side must be either an object (a blessed reference) or a class name (that is, a package name). See perlobj.

    This means that you can't have a string or an expression as a method name. It has to be a simple scalar. So if you do the following, everything should work fine:

    my $method = "prefix_$key"; $f->$method($atr);
      It has to be a scalar, but it doesn't need to be a variable. You can say
      $f->${\("prefix_$key")}($atr);
      However, using a variable is probably clearer.

      Update: added the missing '$' pointed out by ikegami

      --Dave
      Opinions my own; statements of fact may be in error.

        Nice trick, I had never thought about that! :-)
        I've toyed with the idea of making $object->do {expression-yielding-method-name} work. Right now it gives a syntax error.

        Of course, you can do something pretty close by just having a do method:

        sub foo { print "in foo" } sub do { my $self = shift; my $meth = shift; $self->$meth(@_) } $object->do("foo", @args);

        You're missing a $. It should be $f->${\("prefix_$key")}($atr);

Re: Dynamically constructed function calls
by BrowserUk (Pope) on Nov 03, 2004 at 23:59 UTC
    while ( (my ($key,$atr)) = (each %vars)) { print "$key, $atr\n"; my $method = "prefix_$key"; $f->$method( $atr ); }

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: Dynamically constructed function calls
by Anonymous Monk on Nov 04, 2004 at 12:56 UTC
    Just check if you can call it
    $f->can("prefix_$key")->( $atr );

    anon-broquaint

      That doesn't work. $f->can returns a false value, and then you get the message:
      Can't use string ("") as a subroutine ref while "strict refs" in use a +t autol.pl line 21.

      Update:In the pod for UNIVERSAL.pm, it says:

      "can" cannot know whether an object will be able to provide a method through AUTOLOAD, so a return value of undef does not necessarily mean the object will not be able to handle the method call.

        That doesn't work.

        It doesn't work with UNIVERSAL::can, but it could work with an overloaded can:

        { package Foo; my %meth = ( foo => sub { print "Foo?\n" }, bar => sub { print "Bar!\n" }, ); sub baz { print "Baz.\n"; } sub can { $meth{$_[1]} || __PACKAGE__->UNIVERSAL::can($_[1]) } sub AUTOLOAD { use vars '$AUTOLOAD'; (my $methname = $AUTOLOAD) =~ s/.*:://; $meth{$methname}->(@_); } } for (qw(foo bar baz qux)) { if (my $cr = Foo->can($_)) { $cr->(); } else { print "Cannot $_\n"; } }
      anon-broquaint

      Why?


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      Surely, you mean
      $f->can("prefix_$key")->( $f, $atr );

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://405048]
Approved by VSarkiss
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (10)
As of 2014-12-26 08:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (168 votes), past polls