Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things

Re: Creating dispatch table with variable in function name

by Laurent_R (Canon)
on Nov 21, 2017 at 22:10 UTC ( #1203958=note: print w/replies, xml ) Need Help??

in reply to Creating dispatch table with variable in function name

Hmm, I am not sure it is a good idea to do this kind of things. It appears you're really tampering with the symbol tables. This is sort of similar to symbolic references (which are very much frown upon). Or, maybe, this kind of construct should be reserved only for special cases where you want to extend the language, but perhaps shouldn't be done for regular coding. You don't show enough for me to be able to suggest an alternative approach, however.

I am not saying that this is bad, I am not quite sure, but I am just questioning or perhaps only wondering whether this is a good idea. I would be quite interested to know what other monks think about that.

  • Comment on Re: Creating dispatch table with variable in function name

Replies are listed 'Best First'.
Re^2: Creating dispatch table with variable in function name
by Mr. Muskrat (Canon) on Nov 21, 2017 at 22:38 UTC

    It's a simple hash with references to the subroutines so no, this doesn't tamper with the symbol tables.

      No, it's not a simple dispatch table with code refs in it, I certainly would not have any objections to that. What I am possibly worrying about is that the subroutine ref names are dynamically created.

        Personal preference I guess. I see nothing wrong with this. It's far safer than AUTOLOAD, for example, you have to still have to write code for each piece (to create the dispatch table, the subroutines and the look ups).

Re^2: Creating dispatch table with variable in function name
by dsheroh (Prior) on Nov 22, 2017 at 08:18 UTC
    Dispatch tables (hashes with coderefs as values) are a relatively well-known "advanced" technique in Perl and pretty widely used and respected. Personally, I'm using it a lot these days to create programs with a "plugin"-type structure, but it's also used heavily in web frameworks or other contexts where you normally receive a string from an outside source (the UI, a config file, the other end of a network connection, etc.) telling you what to do, then look that string up to find out how to do it. It's simpler, more extensible, and more efficient to match the command to the implementation with a hash lookup than a long if-elsif chain.

    Regarding your concern about it seeming "sort of similar to symbolic references", the most common response I see to "use a variable as a variable name" questions is that you should instead put your data in a hash and look it up by name that way. This is the exact same thing. The hash just contains coderefs instead of static data values.


      I did not have time before to answer in a detailed fashion.

      This is an example (under the debugger) of the use of symbolic references:

      DB<1> ($blue, $red) = qw / b r/; DB<2> say ${$_} for qw /blue red/; b r
      What is happening here is that the second line constructs the variable name $blue from the string "blue" (and the same for red). It works and prints the values of the variables initialized in the first line. It works, yes, but we all know that this technique is very much frown upon, to the point that it is forbidden under the strict pragma, as shown with this one-liner:
      $ perl -Mstrict -E 'our ($blue, $red) = qw / b r/; say ${$_} for qw / +blue red/;' Can't use string ("blue") as a SCALAR ref while "strict refs" in use a +t -e line 1.

      Why does it work? Because it is constructing an entry (variable name) that can be found in the symbol table.

      You can even construct the name with concatenation, doing it this way:

      DB<3> say ${ "bl" . "ue"}; b

      Now the reason I was worried about the OP's code is that the way it constructs the subroutine name is quite similar, and with essentially the same intent: to create a name and look up the symbol table for the subroutine name.

      Again, I'm not saying this is bad, I'm just asking other monks what they think about it.

        I see your point (and obviously misunderstood what you were questioning when I posted my earlier reply), but I'm not convinced that the equivalent
        my %dispatch = ( first => \&_create_first, last => \&_create_last, user => \&_create_user, id => \&_create_id, email => \&_create_email, create_password => \&_create_create_password, );
        is any more virtuous than the map in the OP. Both have the same potential for run-time errors if one or more of the referenced subs doesn't actually exist - simply naming them explicitly does not turn it into a compile-time error:
        $ perl -E 'use strict; use warnings; my %d = ( foo => \&foo ); say "OK +"' OK
        Retyping _create_ every time doesn't actually buy you anything aside from maybe an eyeball error check. (_create_create_password does look a little suspicious to me, but it might still be correct in the OP's code.)
      Thanks for your answer. I am not objecting at all to using dispatch tables, I'm using dispatch tables quite regularly. What I am possibly worrying about is that the subroutine ref names are dynamically created by concatenating various peaces of the name and enclosing them in in &{...} construct.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1203958]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2019-01-21 22:53 GMT
Find Nodes?
    Voting Booth?
    After Perl5, I'm mostly interested in:

    Results (370 votes). Check out past polls.