References to Various Perl Datatypes

References are pointers. A reference variable stores an address. In this way you can store a pointer to a huge chunk of data and later dereference the pointer to get at the data.

What Is a Reference?

You can think of a Perl reference as a scalar whose value is the address in memory of where a piece of data is stored. The piece of data may be a simple value, such as a string, or it might be more complex, such as a record consisting of a name, an occupation, and a series of elements relating to the occupation. In Perl, a reference is a scalar variable that contains the address of some arbitrarily complex piece of data.

Scalar References

One way to create a reference is by using the symbol. You can think of this symbol as the “address of” symbol, because that is what it returns. Here's an example of creating a reference.

$data = 20;                 # scalar: integer value of 20
$rdata = $data;            # reference: address of $data

The scalar $rdata is a reference to $data, which is itself a scalar. Once a reference to a variable is created, you may use it to access the variable that is being referenced. In order to access a variable through a reference, you must use $, the scalar dereferencing operator. Assembly language programmers will recognize this as indirect addressing. All of the ideas having to do with a reference to a scalar are collected into the following example. See the folder Scalar.


% type scalar.pl
#
#   scalar.pl
#
$data = 20;
$rdata = $data;               # create the reference
print "$data
";               # print the data directly
print "$rdata
";              # print the reference
print "$$rdata
";             # print the data indirectly
$$rdata = 50;                  # change the data indirectly
print "$data
";               # prove it
% perl scalar.pl
20
SCALAR(0x1ab2cb8)
20
50
%

If you print a reference, you'll get an address. Normally, this is not what you want, so don't forget to put the extra $ in front of the reference to get the value to which it refers.

Array References

References can be created to any of Perl's data types. To create a reference to an array, proceed as follows.

@values = ( 10, 20, 30 );      # create array
$rvalues = @values;           # create reference to it

As before, if you print $rvalues, you get the following.

ARRAY (0xbe742c)

To get the actual array through the reference, you need to use the array dereferencing operator @.

print "@$rvalues";              # prints 10 20 30

Or, if you want any element of the array—for example, one of the scalars inside the array—then you would use the scalar dereferencing operator $.

print "$$rvalues[0]";       # prints  10
print "$$rvalues[1]";       # prints  20
print "$$rvalues[2]";       # prints  30
print "$$rvalues[-1]";      # prints  30

Here's a program that summarizes the ideas behind a reference to an array. See the folder Array.


% type array.pl
#
#   array.pl
#
@values = ( 10, 20, 30);
$rvalues = @values;          # create the reference
for ( $i = 0; $i < @$rvalues; $i++)
{
     print "$$rvalues[$i]
"; # access element via reference
}
@$rvalues = (120,130,140);    # change array through reference
print "@values
";
% perl array.pl
10
20
30
120 130 140
%

References to arrays have great utility in Perl. Recall that when arguments are sent to a Perl function, they are all collected into the special array @_. If you need to distinguish between two or more arrays sent to a function, this collection strategy becomes a hindrance. However, if you passed references instead of actual arrays, then you could simply dereference them inside the subroutine.

Here is an example of a subroutine that returns the sum of the elements in each array passed to the subroutine. Keep in mind that in this example, the arrays are not passed to the subroutine, but rather a reference to each array is passed. Thus, @_ is filled with references to the real arrays and not with the data in the real arrays. To get to the real arrays, the references must first be dereferenced. See the folder Sums.


% type sums.pl
#
#      sums.pl
#
sub sums
{
       my($sum);
       my(@ans);
       foreach $array (@_)
       {
                $sum = 0;
                foreach $item (@$array)
                {
                        $sum += $item;
                }
                push(@ans, $sum);
        }
        @ans;
}

@a = (10,20,30);
@b = (100,200,300,600);
@c = (5000, 2000, 3000, 4000);
@totals = sums(@a, @b, @c);
print "@totals
";
% perl sums.pl
60 1200 14000
%

The subroutine has nested loops. The outer loop iterates over each reference in the @_ array.

foreach $array (@_)
{

}

The inner loop dereferences each of the references.

foreach $item (@$array)
{
    $sum += $item;
}

Prototypes

The program above works fine, but there is a slight burden to the user of the sums function. The user must remember to pass references rather than the arrays themselves. It would be nice if the user could pass the actual array and have the subroutine behave as if references were passed. This is where a Perl prototype is useful.

A prototype is a set of symbols that informs the Perl subroutine about the type of the incoming parameter. These symbols are placed within a set of parentheses following the name of the function at its definition. Some of the symbols that may be used are

$Force scalar context on incoming arguments.
@Force array reference context.
;Rest of arguments are optional.

In our example, we would like to have at least one argument and, let's say, as many as four arguments to be treated as array references. Thus, we would code

sub sums(@;@@@)
{
    # as before;
}

The line that invokes the sums function would now be

@totals = sums(@a, @b, @c);
print "@totals
"; 

The only restriction is that the caller must not use the & symbol to invoke the subroutine.

Hash References

You may also create a reference to a hash. As usual, the reference operator is , but this time % is the dereferencing operator. See the folder Hash.


% type hash.pl
#
#   hash.pl
#
%convert =  (  1 => one, 2 => two, 3 => three );
$ref = \%convert;
#
#   print all the keys – a likely event
#
print join("
", keys(%$ref)), "
";
#
#   print a value from a key – the most likely event
#
print $$ref{1}, "
";
%

In the above code, notice that %$ref is the entire associative array and that $$ref{1} is the scalar resulting from the 1 key.

% perl hash.pl
1
2
3
one
%

SYNTACTIC SUGAR

To make the encoding of certain dereferences more meaningful, Perl allows a friendlier notation than what we have seen thus far. Suppose we have the following.

@data = (10,20,30,40);
$rdata = @data;

We have seen above that to retrieve an element of the array @data through the reference $rdata, you can code

$$rdata[0];

However, there is another notation that is more user friendly and inherently more meaningful.

$rdata->[0]

There is also an alternative notation for hash references so that if you have a hash such as

%states = ( MD => Annapolis,
            CA => Sacramento,
            NY => "New York City"
          );

and a reference to a hash such as

$rhash = \%states;

you can retrieve values from the hash by using either of the following notations.

print "$$rhash{NY}
";         # New York City
print "$rhash->{NY}
";        # New York City

References to Subroutines

Any Perl data type can have a reference. Thus far, we've seen references to arrays, hashes, and scalars. We now examine references to subroutines. The code below shows how to create a reference to a subroutine and how to invoke the subroutine through the subroutine dereference operator &.

sub square
{
    $_[0] * $_[0]; 
}
$sref = &square;              # create reference
$ans = &$sref(10);             # dereference
print "$ans";                  # prints 100

Now that we know the mechanics of referencing subroutines, we can show an example of sending both an array and a subroutine as arguments to a subroutine. See the folder Compute.


% type compute.pl
#
#   compute.pl
#
sub square
{
    $_[0] * $_[0];
}
sub cube
{
    $_[0] * $_[0] * $_[0];
}

sub compute
{
    my($array,$function) = @_;
    foreach $item (@$array)
    {
          $item = &$function($item);
    }
}
@values = (10,20,30);
compute(@values,&square);
print "@values
";
@data = (5,6,7);
compute(@data,&cube);
print "@data
";
% perl compute.pl
100 400 900
125 216 343
%

In the above code there are two calls to the compute function.

compute(@values,&square);
compute(@data,&cube);

In each case, the arguments are an array reference and a subroutine reference. Therefore, inside the subroutine, we can access each of the arguments through my variables defined in the following statement:

my($array,$function) = @_;

$array is a reference to an array, and $function is a reference to a function. The foreach loop calls the function on each element of the array and changes that element. It will be changed to either its square or its cube, depending upon which function is sent during the call to compute.

foreach $item (@$array)
{
    $item = &$function($item);
}

Remember that within a foreach loop, the iterating variable is a synonym for the actual array element to which it is bound. Thus, the following statement actually changes an array element, the one referred to by $array.

$item = &$function($item);

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.198.173