References

[ Perl tips index ]
[ Subscribe to Perl tips ]

Last week we discussed Scalar::Util and covered, amongst other things, how to weaken references so that circular references no longer cause memory leaks. This week we're going to talk more about references and their many uses.

We'll begin with a brief overview of variable references, which are most commonly seen, and next week we'll look at some more exotic species.

Creating references

We can take a reference to a scalar, hash or array by placing a backslash before its sigil (the punctuation at the start of the variable). Here are some examples:

    my $scalar_ref = \$scalar;
    my $array_ref = \@array;
    my $hash_ref = \%hash;

Note that our references are all contained in scalars. This means that we can use references where ever we would normally require a scalar. We can use references in arrays, or as the values in a hash.

Dereferencing references

Of course, having a reference isn't very useful if we can't retrieve the underlying data structure. To de-reference a variable, we simply put the required sigil back on the front.

    # Add 6 to the value in $scalar_ref.
    $$scalar_ref += 6;

    # Push 'apple' onto the end of the array in $array_ref.
    push @$array_ref, 'apple';

    # Retrieve a list of keys from $hash_ref.
    my @keys = keys %$hash_ref;

When we're dealing with references to arrays and hashes, we often wish to access an individual element, rather than the entire hash or array itself. Perl gives us a shortcut for these simple operations, using what is commonly referred to as arrow notation.

    # Look up an value from an array reference, using its index.
    # Note that we use square-brackets for array look-ups.

    $array_ref->[0];

    # Look up a value from a hash reference, using its key.
    # Note that we use curly-braces for hash look-ups.

    $hash_ref->{flintstone};

Anonymous data structures

If we always had to create the array or hash before we could get a reference to it, there would be much less point. Fortunately, Perl allows us to create anonymous data structures as well.

We can create array and hash references in one step as follows:

    my $array_ref = [ qw/zero one two three four/ ];

    my $hash_ref = {
        zero => 0,
        one => 1,
        two => 2,
        three => 3,
        four => 4,
    };

Notice that we use square brackets to create an array reference and curly braces to create a hash reference. This makes it easy to remember; we use the same type of braces as we do to look up values in the respective data structure. As we use square brackets to look up a value in an array, we use square brackets to create an array reference. Likewise we use curly braces to look up a value in a hash and to create a hash reference.

The above structures are called anonymous arrays and hashes. This is because the array (and hash) itself does not have a name and cannot be accessed separately from the reference.

Uses of variable references

Variable references are primarily used in three kinds of situations:

  1. In object oriented Perl
  2. To pass multiple arrays or hashes into a subroutine
  3. To build complex data structures.

Passing multiple arrays or hashes into a subroutine

If we pass more than one list structure (arrays, hashes or both) into a subroutine Perl helpfully flattens them into one big list and puts all the values in @_, losing the identity of each structure. Sometimes this is what we want, but there will be occasions when we want to pass arrays or hashes that keep their identity. References allow us to do this in a simple and elegant fashion.

    intersection(\@array1, \@array2);

    # Find the intersection between two arrays.
    sub intersection {
        my ($first, $second) = @_;

        # We can now de-reference back into original arrays,
        # or use the arrow notation to access individual
        # elements.

    }

Complex data structures

Arrays and hashes can only contain scalar values. However, since references are scalar values, we can build multi-dimensional data structures through the use of references.

    my %multihash = (
        jarich => {
                company => "Perl Training Australia",
                name => "Jacinta Richardson"
        },
        pjf => {
                company => "Perl Training Australia",
                name => "Paul Fenwick"
        },
        fred => {
                company => "XYZ Retail",
                name => "Fred Bloggs",
        }
    );

    print $multihash{jarich}->{name};

Notice that to build the multi-dimensional hash in this example, we've used anonymous data structures. It's also possible to build hashes of arrays, arrays of hashes and even hashes of arrays of hashes of arrays.

What kind of reference is it?

Sometimes you might need to know what kind of reference you have. Is it a reference to a hash, array or scalar? Or is it a different kind of reference that we haven't covered yet? Fortunately, Perl has a function which will answer this question for us: ref.

    my $scalar_ref = \$scalar;
    my $array_ref = \@array;
    my $hash_ref = \%hash;

    print ref($scalar_ref), "\n";       # Prints SCALAR
    print ref($array_ref), "\n";        # Prints ARRAY
    print ref($hash_ref), "\n";         # Prints HASH

Printing the contents of a reference

Printing the data structure pointed to by a reference can get difficult quickly, especially since the data structures can get quite complex and are not required to conform to any specific structure. Just as arrays can contain both numeric and string data, an array can also contain references to other arrays as well as other hashes, all mixed in with data.

Fortunately the problem of printing the contents of a reference has been solved and thus we have Data::Dumper. This allows us to write:

    use Data::Dumper;

    print Dumper(\%multihash);

to get back:

    $VAR1 = {
              'fred' => {
                          'name' => 'Fred Bloggs',
                          'company' => 'XYZ Retail'
                        },
              'pjf' => {
                         'name' => 'Paul Fenwick',
                         'company' => 'Perl Training Australia'
                       },
              'jarich' => {
                            'name' => 'Jacinta Richardson',
                            'company' => 'Perl Training Australia'
                          }
            };

Data::Dumper can also be used with objects to see their internal state:

    use Data::Dumper;
    use LWP::UserAgent;
    $ua = LWP::UserAgent->new;

    print Dumper $ua;

this prints:

    $VAR1 = bless( {
                     'agent' => 'libwww-perl/5.64',
                     'protocols_forbidden' => undef,
                     'proxy' => undef,
                     'protocols_allowed' => undef,
                     'use_eval' => 1,
                     'max_size' => undef,
                     'from' => undef,
                     'requests_redirectable' => [
                                                  'GET',
                                                  'HEAD'
                                                ],
                     'timeout' => 180,
                     'parse_head' => 1,
                     'no_proxy' => []
                   }, 'LWP::UserAgent' );

Next week we'll talk about some other kinds of references.

[ Perl tips index ]
[ Subscribe to Perl tips ]


This Perl tip and associated text is copyright Perl Training Australia. You may freely distribute this text so long as it is distributed in full with this Copyright noticed attached.

If you have any questions please don't hesitate to contact us:

Email: contact@perltraining.com.au
Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS