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

I have a lookup table of values and formulae, that I reuse many times, like so:

my (%frame_lookup_by) = ( 21 => { desc => "S/W Status", value => sub { $minor_frame_data[0]*256 + $minor_frame_dat +a[1]} , }, 33 => { desc => "HK Subcom", value => sub { $minor_frame_data[1] % 16 } , #modu +lo 16 of w12 }, 117 => { desc => "General Status", value => sub {$minor_frame_data[0]*256 + $minor_frame_data +[1] }, }, 129 => { desc => "Sensor Status", value => sub {$minor_frame_data[0]*256 + $minor_frame_data +[1] }, }, );
However, this hash is used by various subroutines, and @minor_frame_data varies with each time subroutine call. Is there a way to define this once and pass it into each subroutine, where it's updated as necessary? I'd like to avoid globals, obviously, but realize that if I declare
my @minor_frame_data
in each subroutine, the @minor_frame_data in the has of subroutines and the current subroutine are in different lexical scopes, and thus contain different values. I want the values calculated in each subroutine to be derived from the current values in @minor_frame_data. In other words, the following

$ref_frame_lookup_by->{21}->{value}->()
should yield 257 if @minor_data = (1,1). Similarly,

$ref_frame_lookup_by->{33}->{value}->()
should yield 1 if @minor_data = (1,1).

How can I write it so the @minor_frame_data values from the current subroutine are used instead of the ones in the original lexical scope?

Replies are listed 'Best First'.
Re: Updating hash of subroutines
by Zaxo (Archbishop) on Mar 11, 2006 at 01:21 UTC

    That design will give you trouble. It will be confusing to understand and maintain.

    I recommend passing the frame data as arguments to the functions:

    my (%frame_lookup_by) = ( 21 => { desc => "S/W Status", value => sub { $_[0]*256 + $_[1]} , }, 33 => { desc => "HK Subcom", value => sub { $_[1] % 16 }, #modulo 16 of w12 }, 117 => { desc => "General Status", value => sub {$_[0]*256 + $_[1] }, }, 129 => { desc => "Sensor Status", value => sub { $_[0]*256 + $_[1] }, }, );
    With that you can supply the argument that's in the current scope like so:
    my $result = $ref_frame_lookup_by{33}->{value}->(@minor_frame_data);

    After Compline,
    Zaxo

Re: Updating hash of subroutines
by runrig (Abbot) on Mar 11, 2006 at 01:10 UTC
    You can pass in @minor_frame_data to your anonymous subs. E.g.:
    $ref_frame_lookup_by->{33}->{value}->(@minor_frame_data); # With the sub defined as: sub { $_[1] % 16 }
Re: Updating hash of subroutines
by GrandFather (Saint) on Mar 11, 2006 at 01:32 UTC

    You could add the parameters to the dispatch hash:

    use strict; use warnings; my (%frame_lookup_by) = ( 21 => { desc => "S/W Status", value => sub {$_[0]*256 + $_[1]}, }, 33 => { desc => "HK Subcom", value => sub { $_[1] % 16 } , #modulo 16 of w12 }, 117 => { desc => "General Status", value => sub {$_[0]*256 + $_[1] }, }, 129 => { desc => "Sensor Status", value => sub {$_[0]*256 + $_[1] }, }, hash_params => [1, 0], ); print $frame_lookup_by{21}->{value}->(@{$frame_lookup_by{hash_params}} +);

    Prints:

    256

    DWIM is Perl's answer to Gödel
Re: Updating hash of subroutines
by Thelonius (Priest) on Mar 11, 2006 at 04:19 UTC
    Although runrig and Zaxo are probably right that it would be better to pass the parameters explicity, I think what you're looking for is local.

    For example:

    #!perl -w use strict; our (@minor_frame_data); my (%frame_lookup_by) = ( 21 => { desc => "S/W Status", value => sub { $minor_frame_data[0]*256 + $minor_frame_data[1]} , + }, 33 => { desc => "HK Subcom", value => sub { $minor_frame_data[1] % 16 } , #modulo 16 of w12 }, 117 => { desc => "General Status", value => sub {$minor_frame_data[0]*256 + $minor_frame_data[1] }, + }, 129 => { desc => "Sensor Status", value => sub {$minor_frame_data[0]*256 + $minor_frame_data[1] }, + }, ); foo(\%frame_lookup_by); bar(\%frame_lookup_by); sub foo { my ($ref) = @_; local (@minor_frame_data) = (3, 2); print "foo 21 -> ", $ref->{21}->{value}->(), "\n"; } sub bar { my ($ref) = @_; local (@minor_frame_data) = (2, 5); print "bar 21 -> ", $ref->{21}->{value}->(), "\n"; }