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

Hi all,

I'm quite new to perl and trying to understand some scripts. The code I have trouble with is this:

$TotCst{$AppCode{$ID}}->{$CstType{$ID}} += $InvAmnt{$ID};

from this line, I gather this:

hash %TotCst, nested hash %AppCode, key {$ID} ..and this is where I'm stuck.. what is the ->{$CstType{$ID}} saying? I understand that the result of this is incremented by the value of $InvAmnt{$ID}, it's just the ->{$CstType{$ID}} bit that I don't understand. I can see that -> is used in with references and nested hashes/arrays, but not quite how it makes sense in this line.

If anyone can shed light on this I'd be very grateful.

Replies are listed 'Best First'.
Re: Hashes and arrows
by tobyink (Canon) on Mar 13, 2012 at 15:23 UTC

    %AppCode is not a nested hash here. It's a separate hash altogether.

    This:

    $TotCst{$AppCode{$ID}}

    Could have been written as:

    my $this_appcode = $AppCode{$ID}; $TotCst{ $this_appcode }

    It's just taking a value from one hash, and using that value as the key to another hash.

    Your original:

    $TotCst{$AppCode{$ID}}->{$CstType{$ID}} += $InvAmnt{$ID};

    Could have been written as:

    my $this_appcode = $AppCode{$ID}; my $this_csttype = $CstType{$ID}; $TotCst{$this_appcode}->{$this_csttype} += $InvAmnt{$ID};

    So what does the arrow operator actually do? Well, confusingly it performs two different duties in Perl. The first is for object oriented programming: it's the method call operator:

    $object->method(@arguments); Class->method(@arguments);

    But that's not how it's being used here. Here it's the dereferencing operator.

    # Here's an array... my @array = ('foo', 'bar', 'baz'); # Set up a reference (pointer) to the array above. my $array_ref = \@array; # We can access an item in the array like this. warn $array[2]; # But we want to access it via the reference (pointer) # then we need the arrow: warn $array_ref->[2];

    What's happening here? The arrow operator takes the thing on the left, which is a reference (pointer) to some other piece of the data, follows the reference to find the data, and then applies whatever's on the right hand side.

    So in the example above, it's following the $array_ref pointer to find @array then it's applying the index [2] to it.

    As it happens, the arrow is actually optional in your case. This should work just as well:

    $TotCst{$this_appcode}{$this_csttype} += $InvAmnt{$ID};

    This is because inside hashes and arrays, any nested hashes/arrays will always be references, so it is unambiguous that they will always need to be dereferenced. In my $array_ref->[2] example, the arrow operator is not optional.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      This has been a great help, thanks very much for taking the time to explain. I can now see it's a 2 dimensional hash where the 2 levels of keys are values from 2 other hashes - all falling into place now :-)
Re: Hashes and arrows
by jethro (Monsignor) on Mar 13, 2012 at 15:13 UTC

    $CstType{$ID} is the hash key into an unnamed hash that $TotCst{$AppCode{$ID}} points to.

    To get a good picture of it you could use Data::Dumper to show you how $CstType looks like. Data::Dumper shows you hashes and other datastructures exactly as if you had to initialize them with the data in a perl script

Re: Hashes and arrows
by tangent (Parson) on Mar 13, 2012 at 15:11 UTC
    %TotCst is a hash whose values are hash references:
    my $AppCodeID = $AppCode{$ID}; my $CstTypeID = $CstType{$ID}; my $hash_reference = $TotCst{$AppCodeID}; $hash_reference->{$CstTypeID} += $InvAmnt{$ID};
Re: Hashes and arrows
by Anonymous Monk on Mar 13, 2012 at 14:53 UTC