You want to temporarily or permanently redefine a function, but functions can't be assigned to.
To redefine a function, assign a new code reference to the typeglob of the name of the function. Use a local
if you want it to be temporary.
undef &grow; # silence -w complaints of redefinition *grow = \&expand; grow(); # calls expand() { local *grow = \&shrink; # only until this block exists grow(); # calls shrink() }
Unlike a variable but like a handle, a function cannot be directly assigned to. It's just a name. You can manipulate it almost as though it were a variable, because you can directly manipulate the run-time symbol table using typeglobs like *foo
to produce interesting aliasing effects.
Assigning a reference to a typeglob changes what is accessed the next time a symbol of that type is needed. This is what the Exporter does when you import a function or variable from one package into another. Since this is direct manipulation of the package symbol table, it only works on package variables (globals), not lexicals.
*one::var = \%two::Table; # make %one::var alias for %two::Table *one::big = \&two::small; # make &one::big alias for &two::small
A typeglob is something you can use local
on, but not my
. Because of the local
, this aliasing effect is then limited to the duration of the current block.
local *fred = \&barney; # temporarily alias &fred to &barney
If the value assigned to a typeglob is not a reference but itself another typeglob, then all types by that name are aliased. The types aliased in a full typeglob assignment are scalar, array, hash, function, filehandle, directory handle, and format. That means that assigning *Top
=
*Bottom
would make the current package variable $Top
an alias for $Bottom
, @Top
for @Bottom
, %Top
for %Bottom
, and &Top
for &Bottom
. It would even alias the corresponding file and directory handles and formats! You probably don't want to do this.
Use assignments to typeglobs together with closures to clone a bunch of similar functions cheaply and easily. Imagine you wanted a function for HTML generation to help with colors. For example:
$string = red("careful here");
print $string;
<FONT COLOR='red'>careful here</FONT>
You could write the red
function this way:
sub red { "<FONT COLOR='red'>@_</FONT>" }
If you need more colors, you could do something like this:
sub color_font { my $color = shift; return "<FONT COLOR='$color'>@_</FONT>"; } sub red { color_font("red", @_) } sub green { color_font("green", @_) } sub blue { color_font("blue", @_) } sub purple { color_font("purple", @_) } # etc
The similar nature of these functions suggests that there may be a way to factor out the common bit. To do this, use an assignment to an indirect typeglob. If you're running with the highly recommended use
strict
pragma, you must first disable strict 'refs'
for that block.
@colors = qw(red blue green yellow orange purple violet); for my $name (@colors) { no strict 'refs'; *$name = sub { "<FONT COLOR='$name'>@_</FONT>" }; }
These functions all seem independent, but the real code was in fact only compiled once. This technique saves on both compile time and memory use. To create a proper closure, any variables in the anonymous subroutine must be lexicals. That's the reason for the my
on the loop iteration variable.
This is one of the few places where giving a prototype to a closure is sensible. If you wanted to impose scalar context on the arguments of these functions (probably not a wise idea), you could have written it this way instead:
*$name = sub ($) { "<FONT COLOR='$name'>$_[0]</FONT>" };
However, since prototype checking happens at compile time, the preceding assignment happens too late to be useful. So, put the whole loop of assignments within a BEGIN block, forcing it to occur during compilation.
The sections on "Symbol Tables" in Chapter 5 of Programming Perl and in perlmod (1); the section on "Closures" in Chapter 4 of Programming Perl and the discussion of closures in perlref (1); Recipe 10.11; Recipe 11.4
Copyright © 2002 O'Reilly & Associates. All rights reserved.