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 => ®ex_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.
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.