Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
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 exploiting the Monastery: (10)
As of 2014-08-21 19:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (143 votes), past polls