# In the SomeThing module:
package SomeThing;
use overload
'+' => \&myadd,
'-' => \&mysub;
# In your other code:
use SomeThing;
$a = SomeThing->new(57);
$b=5+$a;
if (overload::Overloaded $b) {...} # is $b subject to overloading?
$strval = overload::StrVal $b;
Caveat Scriptor:
This interface is the subject of ongoing
research. Feel free to play with it, but don't be too surprised if the
interface changes subtly (or not so subtly) as it is developed further.
If you rely on it for a mission-critical application, please be sure to
write some good regression tests. (Or perhaps in this case we should
call them "progression" tests.)
This module allows you to substitute class methods or your own subroutines
for standard Perl operators. For example, the code:
package Number;
use overload
"+" => \&add,
"*=" => "muas";
declares function
add()
for addition, and method
muas()
in the Number class (or one of its base classes) for
the assignment form
*=
of multiplication.
Arguments to
use overload
come in key/value pairs. Legal values
are values permitted inside a
&{ ... }
call, so the name of a
subroutine, a reference to a subroutine, or an anonymous subroutine will
all work. Legal keys are listed below.
The subroutine
add()
will be called to execute
$a+$b
if
$a
is a reference to an object
blessed into the package
Number
, or if
$a
is not an object from a package with overloaded addition, but
$b
is a reference to a
Number
. It can
also be called in other situations, like
$a+=7
, or
$a++
. See the section on "Autogeneration".
The functions specified with the
use overload
directive are
typically called with three arguments. (See the "No Method" section later in
this chapter for the four-argument case.) If the corresponding operation is
binary, then the first two arguments are the two arguments of the operation.
However, due to general object-calling conventions, the first argument should
always be an object in the package, so in the situation of
7+$a
, the order of the arguments gets interchanged before the
method is called. It probably does not matter when implementing the addition
method, but whether the arguments are reversed is vital to the subtraction
method. The method can query this information by examining the third argument,
which can take three different values:
-
false (0)
-
The order of arguments is as in the current operation.
-
true (1)
-
The arguments are reversed.
-
undefined
-
The current operation is an assignment variant (as in
$a+=7
), but the usual function is called instead. This additional
information can be used to generate some optimizations.
Unary operations are considered binary operations with the second argument being
undef
. Thus the function that overloads
{"++"}
is called with arguments
($a, undef,
"")
when
$a
++ is executed.
The following operations can be specified with
use overload
:
-
Arithmetic operations
+ - * / % ** << >> x .
+= -= *= /= %= **= <<= >>= x= .=
For these operations a substituted non-assignment variant can be called if
the assignment variant is not available. Methods for operations "
+
",
"
-
", "
+=
", and "
-=
" can be called to automatically generate
increment and decrement methods. The operation "
-
" can be used to
autogenerate missing methods for unary minus or
abs()
.
-
Comparison operations
< <= > >= == != <=>
lt le gt ge eq ne cmp
The
<=>
operator can substitute for any of the other numeric compare
operators, and
cmp
can substitute for any missing string compare
operators. When using
sort
on
arrays,
cmp
is used to compare values subject to
use overload
.
-
Bit and unary operations
& ^ | neg ! ~
"
neg
" stands for unary minus. If the method for
neg
is not
specified, it can be autogenerated using the method for subtraction.
-
Increment and decrement
++ --
If undefined, addition and subtraction methods can be
used instead. These operations are called both in prefix and
postfix form.
-
Transcendental functions
atan2 cos sin exp abs log sqrt
If
abs
is unavailable, it can be autogenerated using methods
for "
<
" or "
<=>
" combined with either unary minus or subtraction.
-
Boolean, string and numeric conversion
bool "" 0+
(Yes, that really is two double-quotes in a row.) If one or two of these
operations are unavailable, the remaining ones can be used instead.
bool
is used in the flow control operators (like
while
and
if
) and for the
trinary "
?:
" operation. These functions can return any
arbitrary Perl value. If the corresponding operation for this value is
overloaded, too, then that operation will be called again with this value.
-
Special
nomethod fallback =
The following sections provide explanation.
Three keys are recognized by Perl that are not covered by the above
descriptions: "
nomethod
",
"
fallback
", and
"
=
".
"
nomethod
" should be followed by a reference to a
function of four parameters. If defined, it is called when the overloading
mechanism cannot find a method for some operation. The first three arguments of
this function coincide with the arguments for the corresponding method if it
were found; the fourth argument is the symbol corresponding to the missing
method. If several methods are tried, the last one is used.
For example,
1-$a
can be equivalent to:
&nomethodMethod($a, 1, 1, "-")
if the pair
"nomethod" => "nomethodMethod"
was specified in the
use
overload
directive.
If some operation cannot be resolved and there is no function assigned to
"
nomethod
", then an exception will be raised via
die
unless
"
fallback
" was specified as a key in a
use overload
directive.
The "
fallback
" key governs what to do if a method for a
particular operation is not found. Three different cases are possible depending
on the value of "
fallback
":
-
undefined
-
Perl tries to use a substituted method (see the section later on
"Autogeneration". If this fails, it then tries to call the method
specified for "
nomethod
"; if missing, an exception will be
raised.
-
true
-
The same as for the undefined value, but no exception is raised. Instead,
Perl silently reverts to what it would have done were there no
use
overload
present.
-
defined, but false
-
No autogeneration is tried. Perl tries to call the method specified
for "
nomethod
", and if this is missing, raises an exception.
The value for "
=
" is a reference to a function with three
arguments; that is, it looks like the other values in
use
overload
. However, it does not overload the Perl assignment
operator. This would rub Camel hair the wrong way.
This operation is called when a
mutator
is applied
to a reference that shares its object with some other reference, such
as:
$a=$b;
$a++;
In order to change
$a
but not
$b
, a copy
of
$$a
is made, and
$a
is assigned a
reference to this new object. This operation is done during execution of the
$a++
, and not during the assignment, (so before the increment
$$a
coincides with
$$b
). This is only
done if
++
is expressed via a method for
"
++
" or "
+=
".
Note that if this operation is expressed via "
+
" (a nonmutator):
$a=$b;
$a=$a+1;
then
$a
does not reference a new copy of
$$a
, since
$$a
does not
appear as an lvalue when the above code is executed.
If the copy constructor is required during the execution of some mutator, but a
method for "
=
" was not specified, it can be
autogenerated as a string copy if the object is a plain scalar.
As an example, the actually executed code for:
$a=$b;
# Something else which does not modify $a or $b...
++$a;
may be:
$a=$b;
# Something else which does not modify $a or $b...
$a = $a->clone(undef, "");
$a->incr(undef, "");
This assumes
$b
is subject to overloading,
"
++
" was overloaded with
\&incr
, and "
=
" was
overloaded with
\&clone
.
If a method for an operation is not found, and the value for
"
fallback
" is true or undefined, Perl tries to
autogenerate a substitute method for the missing operation based on the defined
operations. Autogenerated method substitutions are possible for the following
operations:
-
Assignment forms of arithmetic operations
-
$a+=$b
can use the method for
"
+
" if the method for
"
+=
" is not defined.
-
Conversion operations
-
String, numeric, and Boolean conversion are calculated in terms of one
another if not all of them are defined.
-
Increment and decrement
-
The
++$a
operation can be expressed in terms of
$a+=1
or
$a+1
, and
$a--
in terms of
$a-=1
and
$a-1
.
-
abs($a)
-
Can be expressed in terms of
$a<0
and
-$a
(or
0-$a
).
-
Unary minus
-
Can be expressed in terms of subtraction.
-
Concatenation
-
Can be expressed in terms of string conversion.
-
Comparison operations
-
Can be expressed in terms of its three-valued counterpart: either
<=>
or
cmp
:
<, >, <=, >=, ==, !=
in terms of
<=>
lt, gt, le, ge, eq, ne
in terms of
cmp
-
Copy operator
-
Can be expressed in terms of an assignment to the dereferenced value if this
value is a scalar and not a reference.
WARNING:
One restriction for the comparison operation is that even if, for example,
cmp
returns a blessed reference, the autogenerated
lt
function will produce only a standard logical value based on the
numerical value of the result of
cmp
. In particular, a working
numeric conversion is needed in this case (possibly expressed in terms of
other conversions).
Similarly,
.=
and
x=
operators lose their overloaded
properties if the string conversion substitution is applied.
When you
chop
an object that is subject to overloaded operations, the
object is promoted to a string and its overloading properties are lost.
The same can happen with other operations as well.
Since all
use
directives are executed at compile-time, the only way to
change overloading during run-time is:
eval 'use overload "+" => \&addmethod';
You can also say:
eval 'no overload "+", "--", "<="';
although the use of these constructs during run-time is questionable.
The
overload
module provides the following public functions:
-
overload::StrVal(
arg
)
-
Gives string value of
arg
if stringify overloading is absent.
-
overload::Overloaded(
arg
)
-
Returns true if
arg
is subject to overloading of some operations.
-
overload::Method(
obj
,
op
)
-
Returns the undefined value or a reference to the method that implements
op
.
When Perl is run with the
-Do
switch or its equivalent, overloading
induces diagnostic messages.
Because it is used for overloading, the per-package associative array
%OVERLOAD
now has a special meaning in Perl.
Overloading is not yet inherited via the
@ISA
tree, though
individual methods may be.