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

Function name in a variable, can't recall the concept

by mpersico (Monk)
on Apr 02, 2019 at 14:05 UTC ( [id://1232013]=perlquestion: print w/replies, xml ) Need Help??

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

Or, more accurately, the name of the concept. 'dispatch' is when you use
my %dispatch = ( foo => &somefunc, bar => &someotherfunc, baz => sub {...} );
and 'indirect' is new Some::Class instead of Some::Class->new(). What is the name of the idiom where you do something like
my $funcname = ( $someCondition ? 'foo' : 'bar' ); $funcname->($arg1, $arg2);
I made the 'mistake' of putting this into a piece of Perl code being supervised by a Pythonista (don't ask). Because it took him three rounds of explanations to understand it he wanted to google the concept. He can't find it. And I can't find it either because I think I am using the wrong term. Can someone point me in the direction of my lost google-fu?

Replies are listed 'Best First'.
Re: Function name in a variable, can't recall the concept
by haukex (Archbishop) on Apr 02, 2019 at 14:29 UTC

    I'd say it's just code references, documented in perlref. See also Function object and "First-class functions" on Rosettacode, which have Perl and Python examples. %dispatch is a Dispatch table (and you probably meant to write the code references as foo => \&somefunc). I'm far from a Python expert, but AFAICT, these pieces of code should be pretty much equivalent:

    #!/usr/bin/env perl use warnings; use strict; sub somefunc { print "Hello, $_[0]\n" } my %dispatch = ( foo => \&somefunc, bar => sub { print "World$_[0]\n" }, ); $dispatch{foo}->("Perl"); $dispatch{bar}->("!");
    #!/usr/bin/env python3 def somefunc(x): print("Hello, "+x) dispatch = { 'foo': somefunc, 'bar': lambda x: print("World"+x), } dispatch["foo"]("Perl") dispatch["bar"]("!")

    Note however that using a string as a reference is a symbolic reference and is generally discouraged (and generally not possible under strict): Why it's stupid to `use a variable as a variable name'. Usually it's better to use a hash instead, like the above %dispatch. Update: And your second example is probably better written as my $funcname = ( $someCondition ? \&foo : \&bar );

Re: Function name in a variable, can't recall the concept
by tybalt89 (Monsignor) on Apr 02, 2019 at 14:50 UTC

    Note that 'symbolic names' work perfectly fine as 'method names' under strict and warnings :)

    #!/usr/bin/perl # https://perlmonks.org/?node_id=1232013 use strict; use warnings; my $someCondition = 0; my $arg1 = 'arg1'; my $arg2 = 'arg2'; my $funcname = ( $someCondition ? 'foo' : 'bar' ); SomeClass->$funcname($arg1, $arg2); package SomeClass; sub foo { print "in 'foo' with args: @_\n" } sub bar { print "in 'bar' with args: @_\n" }
Re: Function name in a variable, can't recall the concept
by Eily (Monsignor) on Apr 02, 2019 at 14:27 UTC

    That's a symbolic reference, which is not allowed under strict:

    perl -E "use strict; use warnings; sub hello { say 'Hi' }; my $sub = ' +hello'; $sub->()" Can't use string ("hello") as a subroutine ref while "strict refs" in +use at -e line 1.
    So if your Pythonista were to look into it, he would find a lot of "Don't do that!"

      It's technically the dereference of a symbolic reference that's not allowed. However, there is a (documented) exception:

      \&$sub_name

      This means that while

      $sub_name->()

      isn't allowed,

      (\&$sub_name)->()

      is allowed.

      ($invocant->$method_name() is also allowed under strict.)

        It's technically the dereference of a symbolic reference that's not allowed.
        Is there another case where you would call a variable a symbolic reference when it's not being dereferenced? With eval or when accessing a value through the symbols table?

        You're right about those two exceptions, at least the exceptions are complex enough that beginners shouldn't use them by accident.

        > However, there is an exception:

        More there are:

        use strict; use warnings; sub tst { warn "tst($_[0]) called\n" } my $symbol="tst"; ($::{$symbol})->(1); &{$::{$symbol}}(2); (main->can($symbol))->(3); &{main->can($symbol)}(4);

        C:/Perl_524/bin\perl.exe d:/exp/symbolic_references.pl tst(1) called tst(2) called tst(3) called tst(4) called

        NB:

      • $::{...} is a shortcut for STASH lookup $main::{...} and returns a type-glob
      • ->can(...) returns a coderef

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      Here is another exception, no complaints:

      use strict; use warnings; sub asub { print "heee\n"; } my $x = 'asub'; main->$x();

      bw, bliako

        Not really an exception IMHO because asub is a "method" of the main class/package, so the  -> invocant works as documented.


        Give a man a fish:  <%-{-{-{-<

Re: Function name in a variable, can't recall the concept
by mpersico (Monk) on Apr 02, 2019 at 15:00 UTC
    Today is not my day. When it was mentioned that what I demonstrated in my examples wouldn't work under use strict; I went back and looked at the code again and realized my example was wrong. Here's what I am really doing:
    my $funcname = ( $someCondition ? 'foo' : 'bar' ); $someObject->$funcname($arg1, $arg2);
    It's not "Function name in variable", it's "Method name in variable", and a relevant reference to same is https://perldoc.perl.org/perlobj.html#Method-Call-Variations

      That's OK, from examples above:

      use strict; use warnings; package Object; sub new { return bless \{} } sub foo { printf "hello foo = %s\n", ( caller(0) )[3]; } sub bar { printf "hello bar = %s\n", ( caller(0) )[3]; } package main; my $someObject = Object->new(); my $someCondition = 0; my $funcname = ( $someCondition ? 'foo' : 'bar' ); $someObject->$funcname($funcname); $someCondition = 1; $funcname = ( $someCondition ? 'foo' : 'bar' ); $someObject->$funcname($funcname);
Re: Function name in a variable, can't recall the concept
by mpersico (Monk) on Apr 02, 2019 at 14:48 UTC
    Lovely.

    The code has use strict; use warnings; in it and I don't recall it failing its tests, so now, not only do I have to admit to the Pythonista that I did a Bad Perl Thing, I have to figure out why the code coverage is bad.

    The heck with it. I ain't admitting nothing. I've already coded my way out of it because the two conditions I was dealing with need distinct messages so I am just going to use an if/else and move on.

    Thank you, all.

Re: Function name in a variable, can't recall the concept (introspection with ->can )
by LanX (Saint) on Apr 14, 2019 at 14:16 UTC
    If you want to appease your supervisor use UNIVERSAL::can()

    my $func_name = ( $someCondition ? 'foo' : 'bar' ); my $func_ref = __PACKAGE__->can($func_name); # or other pac +kage $func_ref->($arg1, $arg2);

    I'm sure there is a similar method like can() in Python too.

    > What is the name of the idiom

    When talking to non-Perlers I'd use the general term "introspection"

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    Update:

    ->can is also strict and more stable, since you can easily catch missing subs.

    It won't work with AUTOLOAD though

      No, you shouldn't. can performs a method lookup, not a sub lookup.

      As for not working with AUTOLOAD, that would indicate a bug in the class using AUTOLOAD. It should override can to provide a meaningful result.

        > No, you shouldn't. can performs a method lookup, not a sub lookup.

        ->can does a sub lookup if @ISA is empty, and the content of @ISA is introspectable too.

        And using a package for a module and a class is a pretty dubious concept.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: Function name in a variable, can't recall the concept
by karlgoethebier (Abbot) on Apr 15, 2019 at 15:08 UTC
    "I made the 'mistake'..."

    It looks you did your pythonistic inquisitor a favor - with the result of yet another jesuitic debate here on PM 😎

    "I'm a simple man" B.B. King (1925-2015)

    May i ask what the hell is wrong with your dispatch table solution?

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

    perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1232013]
Approved by marto
Front-paged by Corion
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-04-25 12:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found