- 9.1 Introduction
- 9.2 Operator declarations
- 9.3 Assignment operators
- 9.4 Arithmetic operators
- 9.5 Comparision operator

9. Operator overloading

Defining the action of an operator is much like the definition of a function or procedure, only there are some restrictions on the possible definitions, as will be shown in the subsequent.

Operator overloading is, in essence, a powerful notational tool; but it is also not more than that, since the same results can be obtained with regular function calls. When using operator overloading, It is important to keep in mind that some implicit rules may produce some unexpected results. This will be indicated.

The parameter list for a comparision operator or an arithmetic operator must always contain 2 parameters. The result type of the comparision operator must be

Operator definitions

**Remark: **When compiling in `Delphi` mode or `Objfpc` mode, the result
identifier may be dropped. The result can then be accessed through
the standard `Result` symbol.

If the result identifier is dropped and the compiler is not in one of these modes, a syntax error will occur.

The statement block contains the necessary statements to determine the result of the operation. It can contain arbitrary large pieces of code; it is executed whenever the operation is encountered in some expression. The result of the statement block must always be defined; error conditions are not checked by the compiler, and the code must take care of all possible cases, throwing a run-time error if some error condition is encountered.

In the following, the three types of operator definitions will be examined. As an example, throughout this chapter the following type will be used to define overloaded operators on :

type complex = record re : real; im : real; end;this type will be used in all examples.

The sources of the Run-Time Library contain a unit ucomplex, which contains a complete calculus for complex numbers, based on operator overloading.

The assignment operator defines the action of a assignent of one type of variable to another. The result type must match the type of the variable at the left of the assignment statement, the single parameter to the assignment operator must have the same type as the expression at the right of the assignment operator.

This system can be used to declare a new type, and define an assignment for that type. For instance, to be able to assign a newly defined type 'Complex'

Var C,Z : Complex; // New type complex begin Z:=C; // assignments between complex types. end;You would have to define the following assignment operator:

Operator := (C : Complex) z : complex;

To be able to assign a real type to a complex type as follows:

var R : real; C : complex; begin C:=R; end;the following assignment operator must be defined:

Operator := (r : real) z : complex;As can be seen from this statement, it defines the action of the operator

an example implementation of this could be as follows:

operator := (r : real) z : complex; begin z.re:=r; z.im:=0.0; end;As can be seen in the example, the result identifier (

operator := (r : real) z : complex; begin Result.re:=r; Result.im:=0.0; end;

The assignment operator is also used to convert types from one type to another. The compiler will consider all overloaded assignment operators till it finds one that matches the types of the left hand and right hand expressions. If no such operator is found, a 'type mismatch' error is given.

**Remark: **The assignment operator is not commutative; the compiler will never reverse
the role of the two arguments. in other words, given the above definition of
the assignment operator, the following is *not* possible:

var R : real; C : complex; begin R:=C; end;if the reverse assignment should be possible (this is not so for reals and complex numbers) then the assigment operator must be defined for that as well.

**Remark: **The assignment operator is also used in implicit type conversions. This can
have unwanted effects. Consider the following definitions:

operator := (r : real) z : complex; function exp(c : complex) : complex;then the following assignment will give a type mismatch:

Var r1,r2 : real; begin r1:=exp(r2); end;because the compiler will encounter the definition of the

It is possible to avoid this particular problem by specifying

r1:=system.exp(r2);An experimental solution for this problem exists in the compiler, but is not enabled by default. Maybe someday it will be.

Arithmetic operators define the action of a binary operator. Possible operations are:

**multiplication**- to multiply two types, the
`*`multiplication operator must be overloaded. **division**- to divide two types, the
`/`division operator must be overloaded. **addition**- to add two types, the
`+`addition operator must be overloaded. **substraction**- to substract two types, the
`-`substraction operator must be overloaded. **exponentiation**- to exponentiate two types, the
`**`exponentiation operator must be overloaded.

The definition of an arithmetic operator takes two parameters. The first parameter must be of the type that occurs at the left of the operator, the second parameter must be of the type that is at the right of the arithmetic operator. The result type must match the type that results after the arithmetic operation.

To compile an expression as

var R : real; C,Z : complex; begin C:=R*Z; end;one needs a definition of the multiplication operator as:

Operator * (r : real; z1 : complex) z : complex; begin z.re := z1.re * r; z.im := z1.im * r; end;As can be seen, the first operator is a real, and the second is a complex. The result type is complex.

Multiplication and addition of reals and complexes are commutative operations. The compiler, however, has no notion of this fact so even if a multiplication between a real and a complex is defined, the compiler will not use that definition when it encounters a complex and a real (in that order). It is necessary to define both operations.

So, given the above definition of the multiplication, the compiler will not accept the following statement:

var R : real; C,Z : complex; begin C:=Z*R; end;since the types of

The reason for this behaviour is that it is possible that a multiplication
is not always commutative. e.g. the multiplication of a `(n,m)` with a
`(m,n)` matrix will result in a `(n,n)` matrix, while the
mutiplication of a `(m,n)` with a `(n,m)` matrix is a `(m,m)`
matrix, which needn't be the same in all cases.

The comparision operators that can be overloaded are:

**equal to**- (=) to determine if two variables are equal.
**less than**- () to determine if one variable is less than another.
**greater than**- () to determine if one variable is greater than another.
**greater than or equal to**- () to determine if one variable is greater than or equal to another.
**less than or equal to**- () to determine if one variable is greater than or equal to another.

As an example, the following opetrator allows to compare two complex numbers:

operator = (z1, z2 : complex) b : boolean;the above definition allows comparisions of the following form:

Var C1,C2 : Complex; begin If C1=C2 then Writeln('C1 and C2 are equal'); end;

The comparision operator definition needs 2 parameters, with the types that the operator is meant to compare. Here also, the compiler doesn't apply commutativity; if the two types are different, then it necessary to define 2 comparision operators.

In the case of complex numbers, it is, for instance necessary to define 2 comparsions: one with the complex type first, and one with the real type first.

Given the definitions

operator = (z1 : complex;r : real) b : boolean; operator = (r : real; z1 : complex) b : boolean;the following two comparisions are possible:

Var R,S : Real; C : Complex; begin If (C=R) or (S=C) then Writeln ('Ok'); end;Note that the order of the real and complex type in the two comparisions is reversed.

2000-12-20