Book Home Programming PerlSearch this book

13.6. Overloading Constants

You can change how constants are interpreted by Perl with overload::constant, which is most usefully placed in a package's import method. (If you do this, you should properly invoke overload::remove_constant in the package's unimport method so that the package can clean up after itself when you ask it to.)

Both overload::constant and overload::remove_constant expect a list of key/value pairs. The keys should be any of integer, float, binary, q, and qr, and each value should be the name of a subroutine, an anonymous subroutine, or a code reference that will handle the constants.

sub import { overload::constant ( integer => \&integer_handler,
                                  float   => \&float_handler,
                                  binary  => \&base_handler,
                                  q       => \&string_handler,
                                  qr      => \&regex_handler ) }
Any handlers you provide for integer and float will be invoked whenever the Perl tokener encounters a constant number. This is independent of the use constant pragma; simple statements such as
$year = cube(12) + 1;        # integer
$pi   = 3.14159265358979;    # float
will trigger whatever handler you requested.

The binary key lets you intercept binary, octal, and hexadecimal constants. q handles single-quoted strings (including strings introduced with q) and constant substrings within qq- and qx-quoted strings and here documents. Finally, qr handles constant pieces within regular expressions, as described at the end of Chapter 5, "Pattern Matching".

The handler will be passed three arguments. The first argument is the original constant, in whatever form it was provided to Perl. The second argument is how Perl actually interpreted the constant; for instance, 123_456 will appear as 123456.

The third argument is defined only for strings handled by the q and qr handlers, and will be one of qq, q, s, or tr depending on how the string is to be used. qq means that the string is from an interpolated context, such as double quotes, backticks, an m// match, or the pattern of an s/// substitution. q means that the string is from an uninterpolated context, s means that the constant is a replacement string in an s/// substitution, and tr means that it's a component of a tr/// or y/// expression.

The handler should return a scalar, which will be used in place of the constant. Often, that scalar will be a reference to an overloaded object, but there's nothing preventing you from doing something more dastardly:

package DigitDoubler;    # A module to be placed in DigitDoubler.pm
use overload;

sub import { overload::constant ( integer => \&handler,
                                  float   => \&handler ) }

sub handler {
    my ($orig, $interp, $context) = @_;
    return $interp * 2;          # double all constants
}

1;
Note that handler is shared by both keys, which works okay in this case. Now when you say:
use DigitDoubler;

$trouble = 123;      # trouble is now 246
$jeopardy = 3.21;    # jeopardy is now 6.42
you redefine the world.

If you intercept string constants, it is recommended that you provide a concatenation operator (".") as well, since an interpolated expression like "ab$cd!!" is merely a shortcut for the longer 'ab' . $cd . '!!'. Similarly, negative numbers are considered negations of positive constants, so you should provide a handler for neg when you intercept integers or floats. (We didn't need to do that earlier, because we're returning actual numbers, not overloaded object references.)

Note that overload::constant does not propagate into run-time compilation inside eval, which can be either a bug or a feature depending on how you look at it.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.