in reply to passing arguments in a dispatch table

CharlesClarkson,

I think that you are looking at a closure. As such, data are available as lexicals in the context in which your anonymous sub is defined. Usually you will want $fruit to go out of scope deliberately.

Also, add_entry does nothing with its argument, hence you would not be able to observe a difference:

Warning: untested code

#!/usr/bin/perl -w use strict; $|++; my $dispatch; { my $fruit = [ qw|apple orange pear| ]; $dispatch = { add => sub { return add_entry( $fruit ) }, }; } print scalar localtime, "\n"; sleep 1; print &{ $dispatch->{add} }, " <-- from sub \n";; sleep 1; print scalar localtime, "\n"; sub add_entry{ print scalar localtime, "$_[0] <-- in sub \n"; sleep 1; return scalar localtime; } __END__

Replies are listed 'Best First'.
Re: Re: passing arguments in a dispatch table
by CharlesClarkson (Curate) on Apr 29, 2002 at 02:45 UTC

    Frankly, I think I need an object, but I'm reluctant to use one or a closure. I am introducing a dispatch table as a new concept on a perl beginners mailing list (PBML on Yahoo!). The original script used @book as a global variable. I changed it to $friut for the example above.

    I haven't added the response yet. I do a ton of editing before replying, so I'm still able to scrap this approach.

        Currently, I'm here:
    sub process { my ( $choice, $book ) = @_; my $dispatch = { 1 => \&search_menu, 2 => sub { return \&edit_name($book) }, 3 => sub { return add_entry($book) }, 4 => sub { return delete_entry($book) }, 5 => \&save_default, 6 => \sub{ print "Goodbye!\n"; die; }, e => \sub{ print "Goodbye!\n"; die; }, }; print &{ $dispatch->{ $choice } }; }

    It's a direct move from a group of if - elsif blocks that did the same thing. That's why I'd like to call the subs the same way now. I can introduce better concepts in later posts. I consider this an intermediate approach. Later, $dispatch will be passed to process()as well (which is why I use a hash reference instead of a hash). To help with processing the search menu. $book is reference to @book initally taken from a flat file. memoize immediately comes to mind, but too many beginners shun modules and I don't want to lose my audience.

    I initially scrapped an idea of using a BEGIN block. Perhaps I could combine the two and grab the array reference in each subroutine as someone else mentioned. Though I find using the dispatch table as a source for the arguments that are passed more powerful.

    BEGIN { open FH, 'my_db' or die "Cannot open my_db: $!"; my @book = split /,/, <FH>; sub address_book { return \@book } }

    HTH,
    Charles K. Clarkson
    Clarkson Energy Homes, Inc.
      You say "Frankly, I think I need an object, but I'm reluctant to use one or a closure.", but you're using closures in your code segment above.

      You might want to consider this approach:

      my $dispatch = { 1 => sub { search_menu() }, 2 => sub { my $book = shift; edit_name($book) }, 3 => sub { my $book = shift; add_entry($book) }, 4 => sub { my $book = shift; delete_entry($book) }, 5 => sub { save_default() }, 6 => sub { print "Goodbye!\n"; exit }, e => sub { print "Goodbye!\n"; exit } }; sub process { my ( $choice, $book ) = @_; print $dispatch->{$choice}->($book); }
      Here, we're removing the closure completely, and passing the args directly to the appropriate sub. Did I completely miss what you're trying to do?

        I have two problems with this aproach

        1. $dispatch is not passed to process, making it a global variable. Just what I'd like to get my readers to avoid. Changing the code to pass $dispatch skips a step. As I said: "Later, $dispatch will be passed to process() as well" [emphasis added]. Your getting ahead of the lesson. (Stop being a teacher's pet.)

        2. You're not passing the args directly to the appropriate sub. You're passing the arguments to every subroutine. Let me illustrate the point with a different example.

          my $dispatch = { 1 => sub { return search_menu($current_user) }, 2 => sub { return edit_name($book) }, 3 => sub { return add_entry($book) }, 4 => sub { return delete_entry($book) }, 5 => sub { return save_default($current_user) }, 6 => \sub{ print "Goodbye!\n"; die; }, e => \sub{ print "Goodbye!\n"; die; }, }; &{ $dispatch->{ $choice } };

          Here, the arguments are defined in the dispatch table. I would like to help my readers think in broad terms instead of solving just this one problem. Your solution works fine, but more than 1400 people view these posts and most don't ask questions. My goal is to reach a wide audience with code examples and explanations that can be applied to other problems as well.

        It would seem I'm better at anwering questions than at asking them. Thank you for your reply.


        HTH,
        Charles K. Clarkson
        Clarkson Energy Homes, Inc.