Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Invoking a string reference to a anonymous subroutine

by Superfox il Volpone (Sexton)
on Jan 14, 2014 at 19:03 UTC ( [id://1070587]=perlquestion: print w/replies, xml ) Need Help??

Superfox il Volpone has asked for the wisdom of the Perl Monks concerning the following question:

Hi there, I am defining my private methods as anonymous subs:
my $_parse_element_configuration = sub{ ... }; my $_parse_element_machines = sub{ ... };
suppose I have a reference as :
my $handler = "_parse_element_configuration";
how do I invoke the anonymous sub? I am stuck with:
$self->${$handler}($element); # Use of uninitialized value in method l +ookup at Configuration.pm line 59.


Thanks in advance for any insights,

Kind regards,
s.fox

Replies are listed 'Best First'.
Re: Invoking a string reference to a anonymous subroutine
by davido (Cardinal) on Jan 14, 2014 at 19:14 UTC

    It seems like you're wanting a symbolic reference to refer to a lexical scalar (a my variable), which it can't directly. If, instead of 'my' you were using 'our', you could use the symbolic reference:

    perl -E 'our $p = sub { 1 }; my $q = "p"; say $$q->();'

    ...but then your 'our' variable is a package global, and you're mucking around in the symbol table, which may be counterindicated for maintainability.

    Couldn't this problem be solved with real refs and a hash table used as a dispatch table?

    perl -E 'my %dispatch = ( p => sub { 1 } ); my $q = "p"; say $dispatch +{$q}->();'

    Dave

      Hi Dave

      > It seems like you're wanting a symbolic reference to refer to a lexical scalar (a my variable), which it can't directly.

      indeed... from perlref

      Only package variables (globals, even if localized) are visible to symbolic references. Lexical variables (declared with my()) aren’t in a symbol table, and thus are invisible to this mechanism.

      It never occurred to me, thanks for pointing it out! =)

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Invoking a string reference to a anonymous subroutine
by LanX (Saint) on Jan 14, 2014 at 20:51 UTC
    I prefer dispatch tables since they allow full control. Otherwise use eval to handle lexical symbolic references. The third solution shows a way to note it in one line. HTH! =)
    use warnings; use strict; my $_parse_element_configuration = sub{ print "element_configuration: @_\n" }; my $handler = "_parse_element_configuration"; my $self=42; #--- dispatch table my %parser; $parser{_parse_element_configuration}=$_parse_element_configuration; my $meth=$parser{$handler}; $self->$meth(666); #--- lex sym ref via eval $meth= eval "\$$handler"; $self->$meth(777); #--- abstracted sub handle { my $name=shift; return eval "\$$name"; } handle($handler)->($self,888);
    out:
    element_configuration: 42 666 element_configuration: 42 777 element_configuration: 42 888

    Cheers Rolf

    ( addicted to the Perl Programming Language)

    update

    corrected c&p problem but created duplicate! :-(

      #--- dispatch table ... $self->$meth(666); ... #--- lex sym ref via eval ... $self->$meth(777);

      Don't both of these approaches take the interpreter on a useless (if there is no '42' package/class) or potentially bugilicious (if there is such a package and it contains a  _whatever method) run time search through the  @ISA tree? Why use the  -> operator to pass an ordinary (i.e., non-class/object reference) parameter? Only
          #--- abstracted
          ...
          handle($handler)->($self,888);
      avoids this possibly lengthy detour, but substitutes eval work at runtime.

      Of course, I'm not sure how one would create a '42' package in the first place, but what if it had been  $self = 'Foo'; in your example?

      Hi there,
      thanks for your replies.

      I have tried the third approach by Lanx, but the program returns the following error:
      Variable "$_parse_element_configuration" is not available at (eval 8) +line 2. Use of uninitialized value in subroutine entry at Configuration.pm lin +e 64.
      My code is :
      my $_parse_element_configuration = sub{ ... } sub _handler{ my $function_name = shift; eval "\$$function_name"; }; [...] # invoking the handler _handler("_parse_element_configuration")->($self, $element);
      Where is the problem?

      Kind regards,
      s.fox

      p.s. my Perl version is 5.10, could it be involved?
        > Where is the problem?

        My code worked and the code you are showing now will also work.

        But maybe you should care to define _handler within the scope of your private $_parse... variables to have a proper closure?

        Otherwise Variable "$_parse_element_configuration" is not available at (eval 8) line 2."

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Re: Invoking a string reference to a anonymous subroutine
by runrig (Abbot) on Jan 14, 2014 at 19:17 UTC
    You can do:Update: Ooops, no, you can't do this in your example since your subroutine does not have a name...
    $self->$handler(@arguments);
    Or use the code ref directly (saves a method lookup) (update: and you can do this):
    $self->$_parse_element_configuration(@arguments);
      You can do:

      $self->$handler(@arguments);

      This will only work if the anonymous subroutine reference is assigned to  $handle and not the name of the lexical as in the OP.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-09-08 10:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.