Book Home Programming PerlSearch this book

8.5. Braces, Brackets, and Quoting

In the previous section, we pointed out that ${identifier} is not treated as a symbolic reference. You might wonder how this interacts with reserved words, and the short answer is that it doesn't. Despite the fact that push is a reserved word, these two statements print "pop on over":

$push = "pop on ";
print "${push}over";
The reason is that, historically, this use of braces is how Unix shells have isolated a variable name from subsequent alphanumeric text that would otherwise be interpreted as part of the name. It's how many people expect variable interpolation to work, so we made it work the same way in Perl. But with Perl, the notion extends further and applies to any braces used in generating references, whether or not they're inside quotes. This means that:
print ${push} . 'over';
or even (since spaces never matter):
print ${ push } . 'over';
both print "pop on over", even though the braces are outside of double quotes. The same rule applies to any identifier used for subscripting a hash. So, instead of writing:
$hash{ "aaa" }{ "bbb" }{ "ccc" }
you can just write:
$hash{ aaa }{ bbb }{ ccc }
or:
$hash{aaa}{bbb}{ccc}
and not worry about whether the subscripts are reserved words. So this:
$hash{ shift }
is interpreted as $hash{"shift"}. You can force interpretation as a reserved word by adding anything that makes it more than a mere identifier:
$hash{  shift()  }
$hash{ +shift   }
$hash{  shift @_ }

8.5.1. References Don't Work as Hash Keys

Hash keys are stored internally as strings.[8] If you try to store a reference as a key in a hash, the key value will be converted into a string:

$x{ \$a } = $a;
($key, $value) = each %x;
print $$key;                # WRONG

[8] They're also stored externally as strings, such as when you put them into a DBM file. In fact, DBM files require that their keys (and values) be strings.

We mentioned earlier that you can't convert a string back to a hard reference. So if you try to dereference $key, which contains a mere string, it won't return a hard dereference, but rather a symbolic dereference--and since you probably don't have a variable named SCALAR(0x1fc0e), you won't accomplish what you're attempting. You might want to do something more like:

$r = \@a;
$x{ $r } = $r;
Then at least you can use the hash value, which will be a hard reference, instead of the key, which won't.

Although you can't store a reference as a key, if (as in the earlier example) you use a hard reference in a string context, it is guaranteed to produce a unique string, since the address of the reference is included as part of the resulting string. So you can in fact use a reference as a unique hash key. You just can't dereference it later.

There is one special kind of hash in which you are able to use references as keys. Through the magic[9] of the Tie::RefHash module bundled with Perl, the thing we just said you couldn't do, you can do:

use Tie::RefHash;
tie my %h, 'Tie::RefHash';
%h = (
    ["this", "here"]   => "at home",
    ["that", "there"]  => "elsewhere",
);
while ( my($keyref, $value) = each %h ) {
    print "@$keyref is $value\n";
}
In fact, by tying different implementations to the built-in types, you can make scalars, hashes, and arrays behave in many of the ways we've said you can't. That'll show us! Stupid authors...

[9]Yes, that is a technical term, as you'll notice if you muddle through the mg.c file in the Perl source distribution.

For more about tying, see Chapter 14, "Tied Variables".

8.5.2. Garbage Collection, Circular References, and Weak References

High-level languages typically allow programmers not to worry about deallocating memory when they're done using it. This automatic reclamation process is known as garbage collection. For most purposes, Perl uses a fast and simple reference-based garbage collector.

When a block is exited, its locally scoped variables are normally freed up, but it is possible to hide your garbage so that Perl's garbage collector can't find it. One serious concern is that unreachable memory with a nonzero reference count will normally not get freed. Therefore, circular references are a bad idea:

{               # make $a and $b point to each other
    my ($a, $b);
    $a = \$b;
    $b = \$a;
}
or more simply:
{               # make $a point to itself
    my $a;
    $a = \$a;
}
Even though $a should be deallocated at the end of the block, it isn't. When building recursive data structures, you'll have to break (or weaken; see below) the self-reference yourself if you want to reclaim the memory before your program (or thread) exits. (Upon exit, the memory will be reclaimed for you automatically via a costly but complete mark-and-sweep garbage collection.) If the data structure is an object, you can use a DESTROY method to break the reference automatically; see "Garbage Collection with DESTROY Methods" in Chapter 12, "Objects".

A similar situation can occur with caches--repositories of data designed for faster-than-normal retrieval. Outside the cache, there are references to data inside the cache. The problem occurs when all of those references are deleted, but the cache data with its internal reference remains. The existence of any reference prevents the referent from being reclaimed by Perl, even though we want cache data to disappear as soon as it's no longer needed. As with circular references, we want a reference that doesn't affect the reference count, and therefore doesn't delay garbage collection.

Weak references solve the problems caused by circular references and cache data by allowing you to "weaken" any reference; that is, make it not affect the reference count. When the last nonweak reference to an object is deleted, the object is destroyed and all the weak references to the object are automatically freed.

To use this feature, you need the WeakRef package from CPAN, which contains additional documentation. Weak references are an experimental feature. But hey, somebody's gotta be the guinea pig.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.