Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Can't Reference a Sub by Variable when using Strict

by Dru (Hermit)
on Oct 04, 2004 at 01:53 UTC ( #396091=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks,

The following code works when I'm not using strict, but gives the error
Can't use string ("test1") as a subroutine ref while "strict refs" in use.
with strict enabled. Would someone mind explaining to me why this is?

Thanks,
Dru
#use strict; #!/usr/bin/perl -w use strict; my %lists = ( 'test1' => "stuff", 'test2' => "things" ); for my $i (keys %lists) { &$i(); } sub test1 { print "New message for test1\n"; } sub test2 { print "New message for test2\n"; }

Replies are listed 'Best First'.
Re: Can't Reference a Sub by Variable when using Strict
by tachyon (Chancellor) on Oct 04, 2004 at 02:06 UTC

    Would someone mind explaining to me why this is?

    Because that is what strict was designed to do! You are using a symbolic reference which is almost always a bad idea. You can use hard refs (code refercences in this case) with strict perfectly OK. Perhaps you wanted something like this for use as a dispatch table:

    #!/usr/bin/perl -w use strict; my %lists = ( 'test1' => { func => \&test1, data => 'stuff' }, 'test2' => { func => \&test2, data => 'things' }, ); for my $key (keys %lists) { my $code_ref = $lists{$key}->{func}; my $data = $lists{$key}->{data}; &$code_ref($data); # or use this syntax: $code_ref->($data); } sub test1 { print "New message '$_[0]' for test1\n"; } sub test2 { print "New message '$_[0]' for test2\n"; } __DATA__ New message 'stuff' for test1 New message 'things' for test2

    cheers

    tachyon

Re: Can't Reference a Sub by Variable when using Strict
by davido (Cardinal) on Oct 04, 2004 at 02:14 UTC

    You are using what's known as a symbolic reference, or a soft reference. You really probably don't need or even want to do that. Here are a few alternatives to the same code:

    #-------------------- # Option #1: use strict; my %lists = ( 'test1' => sub { print "New message for test1\n"; }, 'test2' => sub { print "New message for test2\n"; } ); for my $i ( keys %lists ) { $lists{$i}->(); } # ------------------- # Option #2: use strict; sub test1 { print "New message for test1\n"; } sub test2 { print "New message for test2\n"; } my %lists = ( 'test1' => \&test1, 'test2' => \&test2 ); foreach my $i ( keys %lists ) { $lists{$i}->(); }

    This and more is covered in perlreftut and perlref. They're pretty good reads, and terribly helpful if you're trying to grapple with references. As for why using strict causes your code to fail, well, because that's exactly the kind of code strictures is supposed to cause to fail.

    Hope this helps...


    Dave

Re: Can't Reference a Sub by Variable when using Strict
by Fletch (Chancellor) on Oct 04, 2004 at 02:08 UTC

    Erm, because that's what use strict does. You either need to use coderefs (my %lists = ( stuff => \&test1, things => \&test2 );), or use the grandfathered goto syntax:

    for my $i ( keys %lists ) { my $coderef = \&{ $i }; &{ $coderef }; }

    Read perldoc strict for more details.

      Did you try your code under strict? There's a symbolic reference of the same kind in the second line.

        Creating symbolic references to subroutines is quite valid under strictures e.g
        use strict; sub foo { print "It's all good."; } my $subref = \&{ "foo" }; &$subref; __output__ It's all good.
        HTH

        _________
        broquaint

        freebie:~ 1085> cat bar + 10:08:26 use strict; my %lists; for my $i ( keys %lists ) { my $coderef = \&{ $i }; &{ $coderef }(); } freebie:~ 1086> perl -c bar + 10:08:28 bar syntax OK

        This is perfectly valid due to the goto exception I mentioned. If you read perldoc strict:

        There is one exception to this rule: $bar = \&{'foo'}; &$bar; is allowed so that "goto &$AUTOLOAD" would not break unde +r stricture.
Re: Can't Reference a Sub by Variable when using Strict
by pg (Canon) on Oct 04, 2004 at 02:48 UTC

    Just to make the discussion complete, actually you can turn this on and off. However, I am not saying that you should turn the checking off, on the contrary, you should ALWAYS turn it on.

    use warnings; my $ref = "foo"; no strict("refs"); #bad idea &$ref; #works, as strict is turned off for refs use strict("refs"); #good idea &$ref; #don't work any more sub foo { print "foo called once\n"; }

      you should ALWAYS turn it on.

      Don't say that, it's just not true. There are things that can best be done in ways that wouldn't pass under strict refs. But I will say that if you're going to go down that road, you should only do so fully understanding why it is that most everyone panics when they see symbolic refs. They're dangerous when used improperly, and using them properly is difficult to do... and most of the time (not always) there are better ways to do it.

      I'm willing to concede the following: "You should always turn it on, except when you shouldn't, but at those times, know what you're doing."


      Dave

        Hm... this is really about how you look at it, personally I take it religiously.

        The bottom line is that, logically, nothing requires you to turn strict off, with it on, you still can do everything, and much more safer.

Re: Can't Reference a Sub by Variable when using Strict
by !1 (Hermit) on Oct 04, 2004 at 04:44 UTC

    I'm usually partial to this method. Of course, you might not like the fact that it searches @ISA for a class that contains the subroutine. Oh well.

    #!/usr/bin/perl -w use strict; my %lists = ( 'test1' => "stuff", 'test2' => "things", 'test3' => "whatever" ); for my $i (keys %lists) { my $sub = UNIVERSAL::can(__PACKAGE__,$i) || sub { warn "Couldn't cal +l $i" }; &$sub; } sub test1 { print "New message for test1\n"; } sub test2 { print "New message for test2\n"; } __END__ New message for test1 Couldn't call test3 at - line 13. New message for test2

      If you used __PACKAGE__->can( $i ) instead, you could pick up on overridden can() methods and might find out that the package can do much more than you thought it could. That can be very useful sometimes.

Re: Can't Reference a Sub by Variable when using Strict
by lestrrat (Deacon) on Oct 04, 2004 at 02:06 UTC

    Oops. Should have read the code a little more closely...

    keys returns list of keys to the hash. your code is in the value of the hash

    In light of tachyon's comment, here's what I *would have* done

    my %lists = ( 'coderef_name1' => \&coderef1, 'coderef_name2' => \&coderef2 ); while (my($key, $code) = each %lists) { print "executing $key: "; $code->(); }

      Actually that is completely wrong. The keys are called test1 and test2. The subs are called test1 and test2. The sample code runs exactly as expected without strict. The problem is the use of symbolic references, which the sample code uses, but strict disallows. Your code would not run with or without strict.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (2)
As of 2021-10-20 19:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My first memorable Perl project was:







    Results (82 votes). Check out past polls.

    Notices?