Siaris
Simple Things
Syndicate: full/short
Siaris
Categories
General0
News2
Programming2
LanguageBits0
Perl50
Ruby10
VersionControl1
Misc1
Article Calendar
<= May, 2008
S M T W T F S
123
45678910
11121314151617
18192021222324
25262728293031
Search this blog

Key links
External Blogs
Brought to you by ...
Ruby
1and1.com

Tieing Variables

Andrew L. Johnson (First published by ItWorld.com 2001-08-09)

We have seen tie() used in previous articles dealing with DBM files, but we haven’t really talked about what exactly tie() does, or how you can create your own tied classes.

Essentially, tie() allows you to associate a variable with a particular class. Special methods are defined in a tied class that are implicitly called whenever you access this variable. In the Digest::MD5 article (Feb 2001), we tied an ordinary hash to a Berkeley DBM file — thus our hash acted as a persistent database on disk. All the magic of storing and retrieving hash elements from the disk was encapsulated in the DB_File module and was automatically performed whenever we assigned to the hash or retrieved and element from the hash.

You can tie scalars, arrays, hashes, and filehandles by defining an appropriate tied class implementing the behavior you desire. A main difference between a tied class and an ordinary class is that you must use special names (in all caps) for the methods that will be magically called when accessing a variable.

For a concrete example, let’s say we want to have a variable that takes on a random value from a list each time we use it — we will call the class RandSelect (and thus define a module named RandSelect.pm). We want to use this variable as in the following example:

    #!/usr/bin/perl -w
    use strict;
    use RandSelect;

    tie my $rand, 'RandSelect', qw(andrew greg brad john);
    print "The first six random selections are:\n";
    print $rand, "\n" for 1..6;

Which might print out (in one particular run):

    The first six random selections are:
    andrew
    greg
    john
    john
    andrew
    brad

But first we need to create our tied class. Our class begins in the normal fashion:

    package RandSelect;
    use strict;

but things change after this. The constructor for a tied scalar variable class is called TIESCALAR, and its first argument (like class methods in general) will be the class name:

    sub TIESCALAR {
        my $class = shift;
        return bless [@_], $class;
    }

That’s the entire constructor: We grab the class name and then we return a blessed anonymous array containing the remaining arguments passed to the call to the tie() function. We also need to create the method that will be called when we retrieve the value of a tied variable (named FETCH), and the one that will be called when we assign to a tied variable (named STORE). Each of this is an ordinary method call that will receive the object itself as the first argument, and then any remaining arguments (if any).

Even though we’ve tied a scalar variable, our object is really an array reference, so that’s what we deal with when trying to fetch and store values:

    sub FETCH {
        my $self = shift;
        return $self->[rand @$self];
    }

    sub STORE {
        my $self = shift;
        @$self = @{shift()};
    }
    1;
    __END__

Our FETCH routine merely returns a random element from the array reference, and the STORE routine expects an array reference and stores a copy of it in the object. We finish off our module with a single statement returning a true value (just ‘1;’) and that completes the entire tied scalar class. (we really should provide some error checking to ensure an array reference is passed to STORE, but that is an exercise for the reader).

There is already a module on CPAN (Tie::Pick) that is similar to the above but removes each element as it is chosen from the list.

Tieing a scalar is the simplest kind of tied variable to create, there are many more methods that you need to define for tieing arrays and hashes. Further information on tie and creating tied classes can be found in the following Perl documentation pages:

    perldoc -f tie
    perldoc perltie
    perldoc Tie::Scalar
    perldoc Tie::Array
    perldoc Tie::Hash
    perldoc Tie::Handle

One final note: There is a bug in Perl 5.6.1 that sometimes causes a tied variable to be accessed twice when it is interpolated — that is why in the example above I used ‘print $rand, "\n"’ instead of the simpler ‘print "$rand\n"’. This bug should be fixed in 5.6.2.

*****