Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
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.

Replies are listed 'Best First'.
Re: Dynamically constructed function calls
by ikegami (Patriarch) 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.

        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);

        Nice trick, I had never thought about that! :-)
Re: Dynamically constructed function calls
by BrowserUk (Patriarch) 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"; } }
      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.

      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
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (4)
As of 2023-12-11 18:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What's your preferred 'use VERSION' for new CPAN modules in 2023?











    Results (41 votes). Check out past polls.

    Notices?