19.5. Ties
Ties provide a way of replacing the behaviour any type of variable, or of a filehandle. The full mechanism is described in the standard perltie documentation [*] .
Tied variables look exactly like ordinary scalars, arrays, or hashes, but they don't act exactly like them. Their whole purpose is to hide special non-standard behaviour inside a familiar interface. As such, they can be wonderfully Perlish and Lazy, making it easy (for example) to create a variable that automatically self-
# Create a variable whose value cycles from zero to five... use Tie::Cycle; tie my $next_index, 'Tie::Cycle', [0..5]; # Read in monthly results... my @cyclic_buffer; while (my $next_val = prompt '
Every time
$next_index
is used as an index into
@cyclic_buffer
, it moves on to the next value in
[0..5]
. When there are no more values, it
And that's the problem. If
$next_index
had been tied further away from the loop
[*]
, it might easily seem to some maintainer that every new value is being assigned into the same element of the buffer. Tied variables make any code that uses them less
They're also less efficient. A tied variable is actually a wrapper around some blessed object, and so every access on any tied variable requires a method call (instead of being implemented in highly optimized C code). Finally, tied variables can sometimes make your code less robust, as it's very easy to subtly misimplement some aspect of the expected variable behaviour.
Tied variables can always be
# Create an iterator object whose value cycles from zero to five...
use List::Cycle; my $index = List::Cycle->new({ vals => [0..5] });
# Read in monthly results...
my @cyclic_buffer; while (my $next_val = prompt 'Next: ') {
# Saving them in a six-month cyclic buffer...
$cyclic_buffer[$index->next( )] = $next_val;
# And printing the moving average each month...
print 'Half-yearly moving average: ', sum(@cyclic_buffer)/@cyclic_buffer, "\n"; } Often they can also be replaced with a simple subroutine:
# Create a subroutine whose value cycles from zero to five...
{ my $next = -1; my @values = (0..5); sub next_index { return $next = ($next+1) % @values } }
# Read in monthly results...
my @cyclic_buffer; while (my $next_val = prompt 'Next: ') {
# Saving them in a six-month cyclic buffer...
$cyclic_buffer[next_index( )] = $next_val;
# And printing the moving average each month...
print 'Half-yearly moving average: ', sum(@cyclic_buffer)/@cyclic_buffer, "\n"; }
Either way, the distinctive syntax of the method or subroutine calls provides an essential clue to the
|