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

I have a loop in place that has the following within it. The loop goes through the values in an array and splits each array value up into the @vals array to use below. A typical example of the values in the original array are :
101010~0
101010USED~0
A split is then performed on the values (using tilde) to populate the array @vals below. When the loop hits the below check for 101010 it satisfies the if statement. The second time through for 101010USED the if statement isn't satisfied. Why is this the case? Before the loop %vHASH would have it's values set up as follows :
$vHASH{101010}{0} = "something";
$vHASH{101010USED}{0} = "something";

if (!(defined($vHASH{$vals[0]}{$vals[1]}{"SYSTEM"}))) { $vHASH{$vals[0]}{$vals[1]}{"SYSTEM"} = "text"; }
Any explanation to why this is happening would be greatly appreciated. Thanks.

Replies are listed 'Best First'.
Re: Strange Hash Problem
by lostjimmy (Chaplain) on Jul 29, 2009 at 15:25 UTC

    It's hard to diagnose when you don't post a complete example that exhibits the problem.

    Are you sure the array contains what you think it contains? One possibility is that 101010USED~0 actually contains a newline at the end of it, and so your if statement fails. Verify the contents of the array and the hash using Data::Dumper (or something similar)

    use Data::Dumper; print Dumper \@arr, \%vHASH;

    Update: I think I misunderstood the question. The reason this is not working is because at $vHASH{'101010'}{'0'} you have a string value ("something"), and then in your if statement you try to use it as a hash reference. Had you been using strictures (use strict & use warnings), you would have received the following error: Can't use string ("something") as a HASH ref while "strict refs" in use at ./784260.pl line xx.

Re: Strange Hash Problem
by rpike (Scribe) on Jul 29, 2009 at 15:56 UTC
    Thanks for the reply. Here's what I get (notice there is no "Inside of the If" print after the second Data dump): #--- Before I check the if statement above I get : $VAR1 = '101010', '~', '0', 'quantity' ; $VAR2 = { '101010USED' => { '0' => 'ON' }, '101010' => { '0' => 'ON' } }; Inside of the IF : 101010 $VAR1 = '101010USED', '~', '0', 'quantity' ; $VAR2 = { '101010USED' => { '0' => 'ON' }, '101010' => { '0' => 'ON' } }; The code spans over different modules and such leading up to this small loop. As you can tell from the prints above shouldn't the if statement pass both times?
      Hi. Why aren't you using <code></code> tags?
Re: Strange Hash Problem
by rpike (Scribe) on Jul 29, 2009 at 18:23 UTC
    It appears that there is something strange with the hash. If I do something like this :
    $vHash{"101010"}{"S0"} = "text"; $vHash{"101010USED"}{"S0"} = "text"; if (!exists($vHash{"101010"}{"S0"}{"SYSTEM"})) { $vHash{"101010"}{"S0"}{"SYSTEM"} = "TEXT"; print "First<br>"; } if (!exists($vHash{"101010USED"}{"S0"}{"SYSTEM"})) { $vHash{"101010USED"}{"S0"}{"SYSTEM"} = "TEXT"; print "Second<br>"; }
    I only get First printed. If I happen to take the USED in the second if statement and change it to USED101010 and then retry running it I get First and Second print out. Does Perl just look at the first n characters in a hash? Does it see it starts with numbers and then only takes the numbers up until a non-numeric value? Does anyone have an idea to what is happening? Thanks in advance for any help.

      Does Perl just look at the first n characters in a hash?

      No.

      Does it see it starts with numbers and then only takes the numbers up until a non-numeric value?

      No.

      Does anyone have an idea to what is happening?

      Yes. You treat the string "text" as a hash reference. Using use strict; use warnings; would have caught this.

Re: Strange Hash Problem
by rpike (Scribe) on Jul 29, 2009 at 19:47 UTC
    I thought you could assign a value to the hash like
    $vHash{"101010"}{"S0"} = "sometext";
    and then go on and assign an level of hash
    $vHash{"101010USED"}{"S0"}{"SYSTEM"} = "sometext";
    When I changed this first assignment to
    $vHash{"101010"}{"S0"}{"VALUE"} = "sometext";
    it worked fine.
      I thought you could assign a value to the hash like
      $vHash{"101010"}{"S0"} = "sometext";
      and then go on and assign an level of hash
      $vHash{"101010USED"}{"S0"}{"SYSTEM"} = "sometext";
      You can, but you probably shouldn't. The first example puts sometext (which you needn't double-quote, since you aren't interpolating) into the key SO (which you needn't quote at all, since hash keys auto-quote) of the anonymous hash that lives at key 101010 of %vhash. That is, this is the same as
      ${ $vHash{101010} }{S0} = 'sometext';
      The second assignment treats $vHash{101010}{S0} $vHash{101010USED}{S0} as a hash by looking for its entry at key SYSTEM, so Perl obligingly makes it a hash. That is,
      ref $vHash{101010}; # => 'HASH' ref $vHash{101010}{S0}; # => undef ref $vHash{101010USED}; # => 'HASH' ref $vHash{101010USED}{S0}; # => 'HASH'
      While there's no need for the entries of a hash to be homogeneous—it's perfectly OK if some entries are hashes, some are hashes-of-hashes, and so on—it'll probably lead to confusion unless you really mean it.

      UPDATE: As ikegami points out, one of the ways that it can confuse is that you can wind up treating a simple scalar as a (symbolic) hash reference, with the sort of unexpected results that you've discovered.