Other Ways of Using References

Both using the backslash operator to create a reference and putting the reference where a name would be expected to dereference that reference are two common ways of creating and using references. But there are lots of other ways for doing the same things, some of which give you new and complex abilities, and others that provide more readable ways of doing the same thing. In this section, we'll look at some of the other ways to create and use references, as well as explore some of the other issues surrounding references.

Dereferencing List Reference Elements

If you have a reference to a list, one of the more common things you'll want to do with that reference is to get access to the individual elements inside that list—to print them, to sort them, to slice them, and so on. One way to do that is to use the basic syntax you learned about at the start of this lesson, and that we used in the previous example:

print "Minimum number: $$ref[0]
";

This particular line prints the first element of the array pointed to by the reference $ref. If you were going to do the same thing to a hash, you'd use hash syntax, and replace the hash name with the reference:

print "John's last name: $$ref{john} 
";

There's another way to gain access to the list and hash elements pointed to by a reference, one that in many cases (particularly with complex data structures and object-oriented objects) is slightly easier to read. Use the reference, the arrow operator (->), and an array subscript to gain access to list elements pointed to by references:

$first =  $listref->[0];

Note that in this expression there is only one dollar sign. This expression dereferences the list reference in the variable $listref, and returns the 0th element of that list. It is precisely the same as using the standard dereferencing mechanism:

$first = $$listref[0];

To use this syntax with hashes, use the hash reference, the arrow operator ->,, and the hash key in brackets:

$value = $hashref->{$key} ;

This form is just the same as the standard way:

$value = $$hashref{$key} ;

Note

Don't confuse the arrow operator -> with the hash pair operator =>. The former is used to dereference a reference; the latter is the same as a comma and is used to make initializing the contents of hashes easier to read.


We'll come back to this syntax in the section on “Creating Nested Data Structures with References.”

References with Blocks

A third way of dereferencing references is similar to that of basic references; instead of using a reference variable name in place of a regular variable name, you use a block (inside curly brackets) in place of a regular variable name. The block, when evaluated, should return a reference. So, for example, say you had a reference to a list:

$listref = @list;

You could get at the third element of that list using regular dereferencing:

$third = $$listref[3];

Or, through arrow notation:

$third = $listref->[3];

Or, with a block:

$third = ${$listref} [3];

To get the contents or last index of a list through a reference you might use regular de-referencing:

@list = @$listref;
$index = $#$listref;

Or a block:

@list = @{$listref} ;
$index = $#{$listref} ;

This particular block doesn't have much of a point, given that all it does is evaluate the $listref variable, and you could do that just as easily and with fewer characters using a regular dereference. But you could, for example, have called a subroutine inside the block that returned a reference, used an if conditional to choose one reference or another, or put any other expression inside that block. It doesn't have to be a simple variable.

Block dereferencing also allows you to build up some very complex dereferences for very complex structures that use those references. We'll look at this in more detail in the section on “Accessing Elements in Nested Data Structures.”

The ref Function

Say you've got a reference stored in a scalar variable. You'd like to know what kind of data that reference actually points to, so you don't end up trying to multiply lists or get elements out of strings. Perl has a built-in function to do just that called ref.

The ref function takes a scalar for an argument. If the scalar isn't a reference, that is, if it's a string or a number, then ref returns a null string. Otherwise, it returns a string indicating the kind of data the reference points to. Table 19.1 shows the possible values.

Table 19.1. Possible Return Values of ref Function
Return Value Means the Reference Points To
REF Another reference
SCALAR A scalar value
ARRAY An array
HASH A hash
CODE A subroutine
GLOB A typeglob
“” (null string) Not a reference

Note

We'll look at references to subroutines and typeglobs in the “Going Deeper” section of this lesson.


The ref function is most commonly used to test references for their type:

if (ref($ref) eq "ARRAY") {
   foreach $key (@$ref) {
      ...
   }
}  elsif (ref($ref eq "HASH") {
   foreach $key (keys %$ref) {
      ...
   }
}

A Note About Memory and Garbage Collection

One internal side effect of using references concerns the amount of memory that Perl uses up as it runs your script and creates various bits of data. Normally, when your script runs, Perl sets aside bits of memory for your data automatically, and then reclaims the memory when you're done with it. The process of reclaiming the memory—called garbage collection—is different from many other languages, such as C, where you must allocate and free memory on your own.

Perl uses what's called a reference-counting garbage collector. That means for each bit of data, Perl keeps track of the number of references to that data—including the variable name that holds it. If you create a reference to that bit of data, then Perl increments the reference count by 1. If you move the reference to something else, or if a local variable that holds a bit of data disappears at the end of the block or a subroutine, Perl decrements the reference count. When the reference count goes to 0—there are no variables referring to that data, nor any references that point to it—then Perl reclaims the memory that was held by that data.

Normally, this all works automatically and you don't have to do anything about it in your scripts. However, there is a case with references that you have to be careful about: the problem of circular references.

Take these two references:

sub silly {
   my ($ref1, $ref2);
   $ref1 = $ref2;
   $ref2 = $ref1;
   # .. do silly things
}

In this example, the reference in $ref1 points to the thing $ref2 points to, and $ref2 points to the thing $ref1 points to. This is called a circular reference. The difficulty here is when the subroutine is done executing, the local variable names $ref1 and $ref2 disappear, but the data that each one contains still has at least one reference pointing to it, so the memory those references hold cannot be reclaimed. And without the variable names, or a returned reference to one or the other of the references, you can't even get to the data inside that subroutine. It's just going to sit there. And each time that subroutine runs while your script executes, you'll end up with more and more bits of unclaimable memory until Perl takes up all the memory on your system (or your script stops executing).

Circular references are bad things. Although this particular example might seem silly and easy to catch, with complex data structures containing references pointing all over the place, it is possible to accidentally create a circular reference where you don't intend one to be. Consider “cleaning up” any references you use in blocks or subroutines (undef them or assign them to something like 0 or '') to make sure they don't become unclaimed memory.

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

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