Tying Arrays

A class implementing a tied array must define at least the methods TIEARRAY, FETCH, and STORE. There are many optional methods: the ubiquitous DESTROY method, of course, but also the STORESIZE and FETCHSIZE methods used to provide $#array and scalar(@array) access. In addition, CLEAR is triggered when Perl needs to empty the array, and EXTEND when Perl would have pre-extended allocation in a real array.

You may also define the POP, PUSH, SHIFT, UNSHIFT, SPLICE, DELETE, and EXISTS methods if you want the corresponding Perl functions to work on the tied array. The Tie::Array class can serve as a base class to implement the first five of those functions in terms of FETCH and STORE. (Tie::Array's default implementation of DELETE and EXISTS simply calls croak.) As long as you define FETCH and STORE, it doesn't matter what kind of data structure your object contains.

On the other hand, the Tie::StdArray class (defined in the standard Tie::Array module) provides a base class with default methods that assume the object contains a regular array. Here's a simple array-tying class that makes use of this. Because it uses Tie::StdArray as its base class, it only needs to define the methods that should be treated in a nonstandard way.

#!/usr/bin/perl package ClockArray; use Tie::Array; our @ISA = 'Tie::StdArray'; sub FETCH {
 my($self,$place) = @_; $self->[ $place % 12 ];
}
sub STORE {
 my($self,$place,$value) = @_; $self->[ $place % 12 ] = $value;
}
package main; tie my @array, 'ClockArray'; @array = ( "a" ... "z" );
print "@array\n";


When run, the program prints out "y z o p q r s t u v w x". This class provides an array with only a dozen slots, like hours of a clock, numbered 0 through 11. If you ask for the 15th array index, you really get the 3rd one. Think of it as a travel aid for people who haven't learned how to read 24-hour clocks.

Array-Tying Methods

That's the simple way. Now for some nitty-gritty details. To demonstrate, we'll implement an array whose bounds are fixed at its creation. If you try to access anything beyond those bounds, an exception is raised. For example:

use BoundedArray; tie @array, "BoundedArray", 2; $array[0] = "fine"; $array[1] = "good"; $array[2] = "great"; $array[3] = "whoa"; # Prohibited; displays an error message.


The preamble code for the class is as follows:

package BoundedArray; use Carp; use strict;


To avoid having to define SPLICE later, we'll inherit from the Tie::Array class:

use Tie::Array; our @ISA = ("Tie::Array");


That completes our BoundedArray class. It warps the semantics of arrays just a little. But we can do better, and in very much less space.

Notational Convenience

One of the nice things about variables is that they interpolate. One of the not-so-nice things about functions is that they don't. You can use a tied array to make a function that can be interpolated. Suppose you want to interpolate random integers in a string. You can just say:

#!/usr/bin/perl package RandInterp; sub TIEARRAY {
 bless \my $self };
 sub FETCH {
 int rand $_[1] };
 package main; tie @rand, "RandInterp";
for (1,10,100,1000) {
 print "A random integer less than $_ would be $rand[$_]\n";
}
$rand[32] = 5; # Will this reformat our system disk?


When run, this prints:

A random integer less than 1 would be 0 A random integer less than 10 would be 3 A random integer less than 100 would be 46 A random integer less than 1000 would be 755 Can't locate object method "STORE" via package "RandInterp" at foo line 10.


As you can see, it's no big deal that we didn't even implement STORE. It just blows up like normal.