[ Perl tips index ]
[ Subscribe to Perl tips ]

In our last Perl tip, we discussed the hash locking functions available in Hash::Util. This week we'll look at some of the very useful functions available in another one of Perl's standard modules, Scalar::Util.

Weak references

Perl only cleans up memory once its reference count has dropped to zero. The reference count is the number of variables which link to that location. This is illustrated in the following example:

    my $a = "string";    # $a's memory location has 1 reference
    my $b = \$a;        # $a's memory location has 2 references

        my $c = \$a;    # now 3 references

    # $c has gone out of scope, so back to 2 references

    $b = 0;            # now back to 1 reference.

This means that reference loops can result in memory being kept even after the variables have gone out of scope and the memory can no longer be reached. This is called "memory leakage". The following code is a very simple example of this:

        my $a;
        my $b = \$a;
        $a = \$b;

    # $a and $b are out of scope, but the memory cannot be
    # cleaned up

Circular, referential structures often occur in complex situations. Consider an object oriented game of chess. The individual chess pieces need access to the chess board. In return, the board needs to know where each chess piece is. It is difficult to resolve this problem without circular references while still ensuring data encapsulation and no data duplication.

Fortunately, since version 5.6.0, Perl has had a concept of weak references. A weak reference does not cause a reference count to be held on the object it references. Thus, when the reference count reaches 0, the memory is cleaned up and the reference is set to undef.

To weaken a reference, we use Scalar::Util's weaken():

    use Scalar::Util qw/weaken/;
      my $a;

        my $b = "some very big thing";
        $a = \$b;

        weaken($a);    # Make $a a weak reference

    # $b has gone out of scope, since $a was a weak reference
    # $b can now be cleaned up and $a is set to undef

If we want to know if a reference has already been weakened or not, we can use isweak():

    unless( isweak($a) ) {

Is this an object or a reference? What structure does it point to?

If you've ever thought that ref() could be a little bit more helpful, then you might be interested in blessed() and reftype() in the Scalar::Util module.

Perl's inbuilt ref() returns a true value if its argument is a reference. This true value is either the underlying type of the reference (SCALAR, ARRAY, HASH ...) or the name of a class, in the case of an object.

Scalar::Util's blessed() returns a true value if its argument is a blessed reference (ie a Perl object). This true value is the name of the class the reference is blessed into.

Scalar::Util's reftype() returns a true value if its argument is a reference, but always returns the type of the variable referenced. Thus both hash references and references to objects based on hashes returns HASH.

Thus, if you want to find out:

For example:

    use Scalar::Util qw/blessed reftype/;

    my $scalar;

    ref($scalar);        # undef
    blessed($scalar);    # undef
    reftype($scalar);    # undef

    my $hashref = {};

    ref($hashref);        # HASH
    blessed($hashref);    # undef
    reftype($hashref);    # HASH

    my $obj = bless $hashref, "Foo";

    ref($obj);            # Foo
    blessed($obj);        # Foo
    reftype($obj);        # HASH

Dual value variables

Perl's error variable $! returns different values in numerical contexts and string contexts. When used numerically $! returns the C "errno" value and when used in a string context it returns the associated error string. For example:

1Operation not permitted
2No such file or directory
3No such process

Sometimes it would be handy to be able to duplicate this effect in our own error variables. An example is when we're working with the HTTP protocol, we may wish a variable to return '404' as a number, but "page not found" as a string. We may wish We can do this by using Scalar::Util's dualvar():

    use Scalar::Util qw/dualvar/;

    my $response = dualvar 404, "Page not found."

And many more...

There are many other good subroutines provided by Scalar::Util, such as tainted() which enables the programmer to determine if a variable contains tainted data, and readonly() which returns true if is argument is readonly (for example a literal string).

We invite you to refer to the documentation to Scalar::Util to find out more about these functions.

[ 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:

Phone: 03 9354 6001 (Australia)
International: +61 3 9354 6001

Valid XHTML 1.0 Valid CSS