in reply to How to pass a variable to function selected from a hash

In your subroutines,

my $input = @_;

should be something like

my $input = shift();

The way you're doing it, you're looking at the array @_ in scalar context, which, of course, returns the number of elements in the array.

Replies are listed 'Best First'.
Re: Re: How to pass a variable to function selected from a hash
by arturo (Vicar) on Jan 18, 2001 at 04:26 UTC

    You can also do:

    my ($input) = @_;

    I use shift, myself though, when I'm sure there's but one argument.

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Re: How to pass a variable to function selected from a hash
by cat2014 (Monk) on Jan 18, 2001 at 04:27 UTC
    Sweet! That works- thank you!

    I'd always been told that shifting off my input was a Bad Horrible Not Good thing to do, but I guess that in this case, this is better.

      Who told you that? I certainly do not agree that that is true in general.

      Using shift to handle fixed arguments is a standard idiom in Perl. It sometimes not the clearest way to express yourself, but avoiding is not always better either. Use it when it fits. Sometimes that is a matter of taste. In this case I would use it.

      For more on what bit you, see Arrays are not lists.

      For your actual problem you may be glad to find out that there is no need to actually name your handler functions. Just use sub to declare them. When combined with closures (as explained in perlref) this leads to some powerful programming techniques which are as different from standard procedural and OO programing as they are from each other. For more on that I recommend some of my posts that touch on functional techniques (a couple of which are on my home node) and visiting MJD's site and looking around.

      UPDATE
      I would just like to mention that the way to first encounter functional programming is not how I did it. I was told to find out why a several-hundred line program was slow. I spent a good chunk of a day reading something written by a tired programmer in a hurry. When I finally figuring out that a key step was the line that read:

      print join ",", map { &{$field_info{$_}{format}}($deal) } @fields;
      I was far from pleased. And even though I have since learned to like the technique and use it, I make sure that anyone who will have to read my code gets a much gentler introduction to how it works. :-)

      BTW I was successful in speeding the program up. In fact there is a significant performance mistake in the above line. Given that $deal is a data structure and we are looping over a set of deals, what improvement can you find?

        What a great example Tilly! This really got my imagination going. When I first looked at your line of code:
        print join ",", map { &{$field_info{$_}{format}}($deal) } @fields;

        I had no idea where to begin. I couldn't see anything wrong at first. Thankfully, you're post, and the subject at hand, gave enough information that I could infer/guess what the other data structures might look like. In order to optimize your code, I had to imagine & construct the code that wraps around it, in order to simulate it's environment.

        After doing some simple code, I set to look at optimizations. Right away nothing jumped out at me. I thought about hash slices, not using map, using the arrow operator, replacing join with $, and more; some of them worked, others didn't.

        Then, I remembered that we are looping over a set of deals. So I made an @deals array, and started to loop over it. Then I saw it. The map was taking the @fields, and was dereferencing the subref's each time through the @deals loop. Same thing each time through. Now, assuming that @fields is not modified in the loop, we can factor it out, and do it a single time outside of the @deals loop.

        There are more optimizations I could make to my code, but I didn't want to stray too far from attempting to optimize Tilly's code, and loose the point of the excercise.

        Anyhow, this is what I came up with:
        #!/usr/bin/perl -w use strict; #I am sure there are more fields than this my @fields = qw(a b); #Subroutines that return a value. I imagine #you had alot more processing in here, but #this is all make-believe =) my %field_info = ( a => { format => sub {return $_[0]->{deep}{inside}{a}} }, b => { format => sub {return $_[0]->{deep}{inside}{b}} }, ); #Had to simulate a reasonable amount of data, that could #potentially cause a slowdown #Let's make @ deals my @deals; for(my $i = 0; $i < 10000; $i++) { push @deals, { deep => { inside => { a => "a[$i]", b => "b[$i]"} } } +; } #Force commas to be the field seperator inside #print(), so we can drop the join(), and pass an array #to print, rather than one long "joined" string - it should be faster local $, = ','; #Set the output record seperator, so that each call to #print tags on a "\n" after printing out the $deal local $\ = "\n"; #Dereference the subroutines, so that we aren't doing a hash traversal #each time through the @deals loop AND the map. my @dereferenced_subs = map { $_->{format} } @field_info{ @fields }; #Print out each $deal foreach my $deal (@deals) { print map { $_->($deal) } @dereferenced_subs; }

        How's that, did I miss anything?

        Update: I found one optimization, although it could be at the expense of readability. The part where I dereference the subs before going into a loop, I changed to a hash slice to improve the speed of the hash lookup, if there was alot of fields this could make a larger difference. Also, I added a \n after each print, so that the information could be pretty printed.