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

Hi Monks,

I encounter some trouble when I try to dispatch function via hash:

sub write_flag{ print "Success for flag.\n"; } sub write_sets{print "Success for Set.\n"; } sub do_nothing{print "Exit Here\n";} my %Op = ( set_to_flag => \&write_flag, set_tree => \&write_sets, default => \&do_nothing ); sub build_sth{ my ($op_code) = @_; print "\n\nCode: $op_code:\n"; my $op_exec = $Op{$op_code} ; if(defined($op_exec)){ print "it exist: $op_exec\n"; }else{ print "Oop\n"; } }
If I call the build_sth like this:
build_sth('set_to_flag');
It give me:
Oop
If I try to execute the function reference (by &$op_exec()) in build_sth, I will get:
Can't use string ("") as a subroutine ref while "strict refs" in use a +t ...
What happened? How can I get it works?

Replies are listed 'Best First'.
Re: Function reference undef when extract from hash?
by reneeb (Chaplain) on Mar 03, 2008 at 11:09 UTC
    Do you use use strict and use warnings? Where do you call build_sth('set_to_flag')?

    This works:
    #!/usr/bin/perl use strict; use warnings; build_sth( 'set_to_flag' ); sub write_flag{ print "Success for flag.\n"; } sub write_sets{print "Success for Set.\n"; } sub do_nothing{print "Exit Here\n";} sub build_sth{ my ($op_code) = @_; my %Op = ( set_to_flag => \&write_flag, set_tree => \&write_sets, default => \&do_nothing ); my $op_exec = $Op{$op_code} ; if( defined $op_exec ){ $op_exec->(); }else{ print "Oops\n"; } }

      I used strict and warning.

      And the call of the build_sth('set_to_flag') in another function which is called in the main per script:

      (continue with previous code) sub somecall{ build_sth('set_to_flag') } somecall();
      I have checked the previous version where I got trapped. I get the code fail when I move the hash outside of function:
      my %Op = ( set_to_flag => \&write_flag, set_tree => \&write_sets, default => \&do_nothing ); sub build_sth { my ($op_code) = @_; my $op_exec = $Op{$op_code} ; if( defined $op_exec ){ $op_exec->(); }else{ print "Oops\n"; } }
      why the code fail in this case?

        why the code fail in this case?

        The only possibly reason is if build_sth('set_to_flag') is called before my %Op = ( ... ); is executed.

        Otherwise, it doesn't fail.

        sub write_flag { print "write_flag\n"; } sub set_tree { print "set_tree\n"; } sub do_nothing { print "do_nothing\n"; } ... code you provided ... build_sth('set_to_flag'); # Prints write_flag
Re: Function reference undef when extract from hash?
by chromatic (Archbishop) on Mar 03, 2008 at 17:37 UTC

    Declare and assign to %Op before trying to call any functions it contains. The subref assignments occur at runtime, so any code that executes before that will find an empty hash.

      So that I need to declare a subroutine prototype if I declare the hash outside of the function?

        No.

        You need to declare the hash before you try to use it.

        This will work:

        # hash declaration # sub declarations # call some sub that uses the hash

        This will not work:

        # call some sub that uses the hash # hash declaration # sub declarations

        If you want to experiment with this on your own, move all of the code into individual subroutines and call them from main():

        # declare this as a file-scoped lexical my %Op; main(); # subs follow sub main { assign_to_Op(); do_something_else(); } sub assign_to_Op { %Op = ( ... ); } sub do_something_else { my $code = $Op{ ... }; $code->(); }
Re: Function reference undef when extract from hash?
by hipowls (Curate) on Mar 03, 2008 at 11:05 UTC

    $op_exec is a reference to a function and which can be invoked as $op_exec->();

Re: Function reference undef when extract from hash?
by grizzley (Chaplain) on Mar 03, 2008 at 11:43 UTC
    It works as I try it without any changes.