Siaris

Understanding References, Part 2: References to Arrays and Hashes
12 Apr 01 - http://www.siaris.net/index.cgi/Programming/LanguageBits/Perl/20010412.rdoc

Last week we looked at just the basics of taking a reference and then dereferencing it — this week we will look at taking references to arrays and hashes and expand on our dereferencing syntax.

Remember that a scalar variable can hold one thing — basically: a string, a number, or a reference. We’ve already stored a reference to a scalar variable in another scalar variable, but we can also store a reference to an array (or a hash) in a scalar variable as well:

    my @array = (42, 13, 99);
    my $aref  = \@array;

In this case, the variable $aref holds a reference to @array (or, in terms of last week’s discussion, it holds the memory slot number (address) of the array — actually, an array is many slots but we don’t have to worry about that at the moment). But how do we get at the array through the reference?

Recall the syntax we used to dereference a scalar variable:

    my $foo = 42;
    my $bar = \$foo;
    print $$bar;

That last line is actually a slight shortcut — the more explicit version would be:

    print ${$bar};

That is, we put the reference inside of curly braces and then precede it with the type of value of value we are dereferencing — in this case, we use a $ because the value we are getting at is a scalar value. So, for that array case we do the following:

    my @array = (42, 13, 99);
    my $aref  = \@array;
    print "@{$aref}\n";        # print whole array (explicit method)
    print "@$aref\n";          # print whole array (shortcut method)

To get at just one element, let’s first look at getting one element from the real array:

    print $array[1];     # prints: 13

Breaking this down we have: a type symbol for the type of value (arrays hold scalar values as elements), the array name, and the index. To do the same thing with a reference we replace the array name with the reference to it:

    print ${$aref}[1];  # explicit method
    print $$aref[1];    # shortcut method

We can do the same things with hashes as well:

    my %hash = ( name => 'Andrew', beer => 'Dark Ale' );
    my $href = \%hash;

    print "${$href}{name} ";       # explicit
    print "drinks $$href{beer}\n"; # shortcut

    # or to iterate over the hash:

    foreach my $key ( keys %$href ) {
        print "$key : $$href{$key}\n";
    }

How do references help us? One useful thing they allow us to do is to pass multiple arrays and/or hashes into a subroutine. Remember that a subroutine receives its parameters as one long flat list of arguments, so to create a subroutine that compares two arrays to see if they contain the same numerical elements we need to use references:

    my @one = (42, 13, 99, 72, 1);
    my @two = (42, 13, 99, 72, 1);
    if ( cmp_arrays(\@one, \@two) ) {
        print "Arrays are the same\n";
    } else {
        print "Arrays are not the same\n";
    }

    sub cmp_arrays {
        my ($one, $two) = @_;
        return 0 unless @$one == @$two; # check sizes
        foreach my $i (0 .. @$one - 1) {
            return 0 unless $$one[$i] == $$two[$i];
        }
        return 1;
    }

Next week we will look at alternate dereferencing methods and building nested data structures such as multidimensional arrays and hashes.

*****