Objects Overloading Operators
Operators
Maple objects can implement methods to allow objects to be used with the standard Maple operator syntax. The following example shows how an object can implement the ^ operator.
module MyInteger() option object; local value := 0; export ModuleCopy::static := proc( mi::MyInteger, proto::MyInteger, v::integer, $ ) if ( _npassed = 3 ) then mi:-value := v; else mi:-value := proto:-value; end if; end proc; export ModuleApply::static := proc( ) Object( MyInteger, _passed ); end proc; export toInt::static := proc( mi::MyInteger, $ ) mi:-value; end proc; export ModulePrint::static := proc( mi::MyInteger ) mi:-value; end proc; export `^`::static := proc( i1::MyInteger, i2::MyInteger ) MyInteger( i1:-value ^ i2:-value ); end proc; end module:
i1 := MyInteger( 1 ):
toInt( i1 );
1
i2 := MyInteger( 2 ):
toInt( i2 );
2
i3 := MyInteger( 3 ):
toInt( i3 );
3
i8 := i2^i3:
toInt( i8 );
8
Supported Operators
The following operators can be implemented by an object:
+, -, *, /, ^, !, .
=, <>, <, <=, >, >=
and, or, not, xor, implies
intersect, union, minus, subset, in
[], {}, ?[], @, @@, ~
&*, &name
::
The following operators, in particular, cannot be overridden:
?(), :-, ,, ->, :=
Note: These lists are not the same as the operators that can and cannot be overridden using a use statement.
Implementing Operators
In general, implementing operators is similar to implementing any object method. See the Overview of Object Methods page for more details.
Whenever an object with an overloaded operator appears in an expression using that operator the overloaded operator will be used, including within the definition of the operator itself. Thus one must be careful to avoid writing an infinitely recursive routine. To use a different version of the operator, the fully qualified functional form should be used.
Special Considerations
The + and * Operators
The + and * operators are n-ary as opposed to binary. In other words, a large sum or product containing objects will be converted to a single call to the + or * method, with each term passed as an argument. Thus the operator should be able to accept more than two arguments.
By accepting more than two arguments, the operator can analyze the entire statement at once and work intelligently on multiple objects in a single expression.
The following + operator implements addition for any number of MyInteger objects:
export `+`::static := proc( ints::seq(MyInteger), $ ) local x; MyInteger( add( toInt(x), x in [ints] ) ); end proc:
These two operators may also return a sequence instead of a single value. In this case, the sequence will be converted into a unevaluated sum or product DAG. This only occurs when the function is called as an operator or method, but not if called as a fully qualified function.
For example:
module Obj() option object; export ModuleApply::static := proc( ) 'Obj'; end proc; export `*`::static := proc( ) local x; op( map( x->f(x), [_passed] ) ); end proc; end module;
moduleObjoptionobject;end module
When the * operator defined above is called with multiple elements, it returns an expression sequence instead of a single element. When used as an operator, the expression sequence is converted to a product.
Obj * x * y;
f⁡moduleObjoptionobject;end module⁢f⁡x⁢f⁡y
Likewise when the operator is called as a member function:
`*`( Obj, x, y );
However, when called as a fully qualified function, the conversion does not occur.
Obj:-`*`( Obj, x, y );
f⁡moduleObjoptionobject;end module,f⁡x,f⁡y
The - and / Operators
If an object overrides the - and / operators, the corresponding procedures are only invoked with a single argument, as `-`(obj) or `/`(obj), respectively.
For an expression like obj1 - obj2, Maple first calls `-`(obj2), and then, if the `+` operator is also overloaded, calls it as `+`(obj1, mobj2) where mobj2 is the result of the first call. If the `-` operator is not overloaded but the `*` operator is, then Maple calls `*`(obj1, -1) instead of `-`(obj1).
Similarly, for obj1 / obj2, Maple first calls `/`(obj2), and then, if the `*` operator is also overloaded, calls it as `*`(obj1, dobj2) where dobj2 is the result of the first call. If the `/` operator is not overloaded but the `^` operator is, then Maple calls `^`(obj1, -1) instead of `/`(obj1).
Because of these "fallback" rules (using `*` if `-` is not defined, and using `^` if `/` is not defined), it is typically only useful to overload these operators if the implementation does something different than the fallback would do.
The = and <> Operators
An object can implement the = and <> operators. If an object implements the = operator but not the <> operator, the = operator will be used when <> is called in the following way:
true becomes false
false becomes true
FAIL remains unchanged
other values x are returned as not x
The and, or, xor, implies and not Operators
When evaluating an expression involving a Boolean operator and an object (myObject and something), this will result in a call to the corresponding method. When evaluating the function form (`and`(myObject, something)), this initially results in the operator form being constructed but not evaluated. When the operator form is later evaluated (e.g. by evalb or in the condition of an if statement) the method will be invoked.
Consequences of Implementing ?[]
The indexing operator, ?[], is called when an object is indexed (for example, object[index]). As objects are implemented on top of modules, the indexing syntax has a default functionality for accessing module members, module[member]. If an object overloads the indexing operator, this default behavior is lost, and the module:-member syntax must be used instead. It is up to the implementer to decide whether to support the module[member] syntax in the ?[] export.
Together with lowerbound and upperbound, the indexing operator can be used for implementing iteration over an object, as an alternative to implementing a ModuleIterator procedure. See ModuleIterator for more details.
Overloading the || Operator
The || operator is the name concatenation operator. Thus the left hand side of a || statement evaluates to a name. This means that if a name whose value is an object appears on the left hand side of a || statement, that object will not be searched for an overloaded ||.
The || operator is used when evaluating the cat routine. As cat uses the normal evaluation rules, a name with an object for a value will be searched for an overloaded ||, regardless of where it appears in the argument sequence.
The in Operator
The operator in (displayed as ∈) can be used to test membership in lists and sets. If an object does not export in but does export member, then Maple will use member to decide membership: evaluation of the expression a∈b in a Boolean context, where a or b (or both) are objects exporting member results in a call to that procedure. Evaluation in a Boolean context happens, for example, in the condition of an if statement or in a call to evalb.
The help page Object,builtin explains the details of writing a member export.
See Also
cat
indexing operator
module
Object
object
object/builtin
object/create
object/method
procedure
use
Download Help Document