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

Dear Monks,
I am running into this weird problem with variable scoping.
Below is my sub-routine, populatemessagedefs. I am passing hash reference and a string to the sub-routine.
Scope of the sub-routine is to populate hash by splitting the string ($Everythingelse) by ',' and inserting it in the hash.
Example <\br> $Everythingelse holds (Tom,18,Jack,22,Tim,30)
The sub-routine iterates in the foreach loop and inserts following in hash
Result Set:
Key->Tom Value->18
Key->Jack Value->22
Key->Tim Value->30
The problem is after every ‘foreach’ iteration '$i' resets to 0, even if I increment value of $i.
Am I missing something completely obvious?
sub populatemessagedefs() { my ($ref_to_msg_defs,$Everythingelse) = @_; my $temp_value; my $temp_key; my @Interface_Message_List = split (',',$Everythingelse); my $i=0; foreach my $field(@Interface_Message_List) { #In next iteration $i is ‘0’ again if ($i == 0) { $temp_key = $field; $i++; #Value of $i is 1 now } elsif ($i == 1) { $temp_value = $field; if (exists $ref_to_msg_defs->{$temp_key}) { if ($field > $ref_to_msg_defs->{$temp_key}) { $ref_to_msg_defs{$temp_key} = $field; $i--; } } else { $ref_to_msg_defs{$temp_key} = $field; $i--; } } } }

Replies are listed 'Best First'.
Re: problem with variable scoping
by roboticus (Chancellor) on Mar 18, 2010 at 17:01 UTC

    parth00:

    I don't see your bug, but why not just use something like (untested):

    sub populatemessagedefs { my $hashref = shift; my $string = shift; my @list = split(',', $string); while (@list) { my $k = shift @list; my $v = shift @list; $$hashref{$k}=$v unless exists($$hashref{$k}) and $v < += $$hashref{$k}; } my %hash2 = split(',', $string); }

    Update 2: I missed the bit where you're keeping the largest value for each key. Corrected code above, original code below.

    sub populatemessagedefs { my $hashref = shift; my $string = shift; %$hashref = (%$hashref, split(',',$string)); }

    Update: I forgot to mention--you don't want to use a prototype on your subroutine definition.

    ...roboticus

Re: problem with variable scoping
by almut (Canon) on Mar 18, 2010 at 17:02 UTC

    Is it always zero at the beginning of the loop body, or on every other iteration?  In case of the latter, it could be because the conditions you're testing are such that $i gets decremented in the elsif branch every time it has become 1.  Heavily simplified, like this:

    my $i=0; foreach my $field (qw(foo bar baz quux)) { print "i=$i\n"; if ($i == 0) { $i++; # increment } elsif ($i == 1) { if (0) { if (0) { $i--; } } else { $i--; # decrement } } } __END__ i=0 i=1 i=0 i=1
Re: problem with variable scoping
by kennethk (Abbot) on Mar 18, 2010 at 17:03 UTC
    The code you've posted does not display the error to describe. If I run the following (lightly modified)

    #!/usr/bin/perl use strict; use warnings; &populatemessagedefs(undef, '1,2,3,4,5,6'); sub populatemessagedefs() { my ($ref_to_msg_defs,$Everythingelse) = @_; my $temp_value; my $temp_key; my @Interface_Message_List = split (',',$Everythingelse); my $i=0; my %ref_to_msg_defs; foreach my $field(@Interface_Message_List) { print "$i\n"; #In next iteration $i is ‘0’ again if ($i == 0) { $temp_key = $field; $i++; #Value of $i is 1 now } elsif ($i == 1) { $temp_value = $field; if (exists $ref_to_msg_defs->{$temp_key}) { if ($field > $ref_to_msg_defs->{$temp_key}) { $ref_to_msg_defs{$temp_key} = $field; $i--; } } else { $ref_to_msg_defs{$temp_key} = $field; $i--; } } } }

    I get

    0 1 0 1 0 1

    which I'd expect. Two items of note for you:

    1. You are using Prototypes incorrectly by declaring your subroutine with sub populatemessagedefs(). You expect two scalar arguments, not zero as you've written there. Unless you know what prototypes are and what they are not, you should really replace that line with sub populatemessagedefs.
    2. You never use $ref_to_msg_defs, which I assume is a hash reference. Rather, in your code you use $ref_to_msg_defs{$temp_key}, which accesses the hash %ref_to_msg_defs, which is not declared in your code. In order to run under strict, I had to declare the appropriate local hash.
Re: problem with variable scoping
by cdarke (Prior) on Mar 18, 2010 at 17:11 UTC
    I do not get your symptoms, $i was 0 first time around, then 1, then 0, then 1. However %ref_to_msg_defs was not defined, and the prototype you have in sub populatemessagedefs() means 'no parameters', which is probably not what you want. But I don't think that will cause your problem.
Re: problem with variable scoping
by biohisham (Priest) on Mar 18, 2010 at 18:11 UTC
    What would the purpose of switching on and off by alternating the values of $i between 0 and 1 ??, I could not see through it clearly but well, I thought of a simplistic approach guaranteed that your string contains data that can be accommodated uniformly...
    #!/usr/local/bin/perl use strict; use warnings; my $hashRef = {}; my $string = "Tom, 18, Jack, 22, Tim, 30"; populateHash($hashRef,$string); sub populateHash{ my ($hashRef,$scopedString) = @_; my @stringArray = split (', ',$scopedString); %$hashRef = @stringArray; return $hashRef; } use Data::Dumper; print Dumper(\%$hashRef);


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.