Полезная информация

Programming Perl

Programming PerlSearch this book
Previous: 7.2.47 ODBM_File - Tied Access to ODBM FilesChapter 7
The Standard Perl Library
Next: 7.2.49 POSIX - Perl Interface to IEEE Std 1003.1
 

7.2.48 overload - Overload Perl's Mathematical Operations

# 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".

7.2.48.1 Calling conventions for binary operations

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.

7.2.48.2 Calling conventions for unary operations

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.

7.2.48.3 Overloadable operations

The following operations can be specified with use overload:

Three keys are recognized by Perl that are not covered by the above descriptions: "nomethod", "fallback", and "=".

7.2.48.4 No method

"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.

7.2.48.5 Fallback

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.

7.2.48.6 Copy constructor

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.

7.2.48.7 Autogeneration

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.

7.2.48.8 Run-time overloading

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.

7.2.48.9 Public functions

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.

7.2.48.10 Diagnostics

When Perl is run with the -Do switch or its equivalent, overloading induces diagnostic messages.

7.2.48.11 Bugs

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.


Previous: 7.2.47 ODBM_File - Tied Access to ODBM FilesProgramming PerlNext: 7.2.49 POSIX - Perl Interface to IEEE Std 1003.1
7.2.47 ODBM_File - Tied Access to ODBM FilesBook Index7.2.49 POSIX - Perl Interface to IEEE Std 1003.1