Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re^5: Creating dispatch table with variable in function name

by AnomalousMonk (Archbishop)
on Nov 22, 2017 at 16:45 UTC ( [id://1204037]=note: print w/replies, xml ) Need Help??


in reply to Re^4: Creating dispatch table with variable in function name
in thread Creating dispatch table with variable in function name

Per Laurent_R: "... I am ... worrying ... that the subroutine ref names are dynamically created."
Per Mr. Muskrat: "Personal preference ... I see nothing wrong ... you have to still have to write code for each piece ..."

What worries me is that, while strict is perfectly happy with it, the code below has a run-time error that may not be triggered for hours/days/weeks/months/...

c:\@Work\Perl\monks>perl -MData::Dump -le "use warnings; use strict; ;; sub hiya { print 'hi from ', (caller(1))[3]; } ;; sub _x_foo { hiya; }; sub _x_bar { hiya; }; ;; my %disp = map { $_ => \&{ '_x_' . $_ } } qw(foo bar zot); dd \%disp; ;; $disp{foo}->(); $disp{zot}->(); $disp{bar}->(); " { bar => sub { "???" }, foo => sub { "???" }, zot => sub { "???" } } hi from main::_x_foo Undefined subroutine &main::_x_zot called at -e line 1.
You have to write code for each piece in order for the whole thing to work reliably, but you may not discover that it doesn't until a very inopportune moment. If everything could be thoroughly tested prior to deployment, the queasy feeling in my stomach might be eased a bit, but even so...


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

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

    What worries me is that, while strict is perfectly happy with it, the code below has a run-time error that may not be triggered for hours/days/weeks/months/...

    Okay... So does the equivalent static dispatch table.

    use strict; use warnings; ;; sub hiya { print 'hi from ', (caller(1))[3]; } ;; sub _x_foo { hiya; }; sub _x_bar { hiya; }; ;; my %disp = ( foo => \&_x_foo, bar => \&_x_bar, zot => \&_x_zot, ); dd \%disp; ;; $disp{foo}->(); $disp{zot}->(); $disp{bar}->();

    You have to write code for each piece in order for the whole thing to work reliably, but you may not discover that it doesn't until a very inopportune moment. If everything could be thoroughly tested prior to deployment, the queasy feeling in my stomach might be eased a bit, but even so...

    This is true for all Perl code though. There's a gajillion ways to write a script that "compiles" with strictures enabled but fails at runtime. This is why we write tests (unit, functional, etc).

      So does the equivalent static dispatch table.

      Hmm... I hadn't tested that. Ok, how about:

      c:\@Work\Perl\monks>perl -MData::Dump -le "use warnings; use strict; ;; sub _x_foo { hiya(@_); } sub _x_bar { hiya(@_); } ;; my %disp = map { my $agent = qq{_x_$_}; $_ => __PACKAGE__->UNIVERSAL::can($agent) || die qq{dispatch via unknown agent '$agent'}; } qw(foo bar BAM) ; ::dd \%disp; ;; sub hiya { print 'hi from ', (caller(1))[3], qq{ (@_)}; } ;; $disp{foo}(); $disp{POW}(qw(x y z)); $disp{bar}(99, 88); " dispatch via unknown agent '_x_BAM' at -e line 1.
      This throws both compile- and run-time exceptions, although I don't like the obscure wording of the run-time error message.

      How about putting the whole thing into a lexically scoped package? This allows full control of the composition of the run-time error message, and makes the dispatch hash entirely private. It's also all ready to be moved off to its own module. I can't say I'm fond the  Dispatch::me('foo') invocation syntax, but putting this in its own module would give you some more syntax choices.

      c:\@Work\Perl\monks>perl -MData::Dump -le "use warnings; use strict; ;; { package Dispatch; ;; sub _x_foo { hiya(@_); } sub _x_bar { hiya(@_); } ;; my %disp = map { my $agent = qq{_x_$_}; $_ => __PACKAGE__->UNIVERSAL::can($agent) || die qq{dispatch via unknown agent '$agent'}; } qw(foo bar BAM) ; ::dd \%disp; ;; sub me { my $tag = shift; ;; die qq{unknown dispatcher '$tag' used} unless exists $disp{$tag}; ;; return $disp{$tag}(@_); } ;; sub hiya { print 'hi from ', (caller(1))[3], qq{ (@_)}; } } ;; Dispatch::me('foo'); Dispatch::me('POW', qw(x y z)); Dispatch::me('bar', 99, 88); " dispatch via unknown agent '_x_BAM' at -e line 1.


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

Re^6: Creating dispatch table with variable in function name
by Mr. Muskrat (Canon) on Nov 22, 2017 at 17:27 UTC

    Add this to the script:

    sub AUTOLOAD { our $AUTOLOAD; warn sprintf "unknown subroutine '%s' called with params: '%s'\n", $ +AUTOLOAD, join "', '", @_; }

    Output:
    { bar => sub { ... }, foo => sub { ... }, zot => sub { ... } }
    unknown subroutine 'main::_x_zot' called with params: ''
    hi from main::_x_foohi from main::_x_bar

    Update: Yes, dynamically generated dispatch tables can cause problems if you aren't careful but that's true enough without them too. You can protect against most (all?) of the potential issues if you try. I'm not going to tell anything that they should or should not use dynamically generated dispatch tables in production. I do want to provide enough information for someone to be able to make that decision for themself.

      That might actually be worse. Instead of coming to a screeching halt, the process would produce a warning message that might get tucked away in an error log somewhere and go unnoticed for days/weeks/months/years/ever.


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

        The whole point of that post was to show that you can choose how to deal with it.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (8)
As of 2024-04-16 08:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found