Operator Overloading (Delphi)

From RAD Studio
Jump to: navigation, search

Go Up to Classes and Objects Index


This topic describes Delphi's operator methods and how to overload them.

About Operator Overloading

Delphi allows certain functions, or "operators", to be overloaded within record declarations. The name of the operator function maps to a symbolic representation in source code. For example, the Add operator maps to the + symbol.

The compiler generates a call to the appropriate overload, matching the context (that is, the return type, and type of parameters used in the call), to the signature of the operator function.

The following table shows the Delphi operators that can be overloaded:

Operator Category Declaration Signature Symbol Mapping

Implicit

Conversion

Implicit(a : type) : resultType;

implicit typecast

Explicit

Conversion

Explicit(a: type) : resultType;

explicit typecast

Negative

Unary

Negative(a: type) : resultType;

-

Positive

Unary

Positive(a: type): resultType;

+

Inc

Unary

Inc(a: type) : resultType;

Inc

Dec

Unary

Dec(a: type): resultType

Dec

LogicalNot

Unary

LogicalNot(a: type): resultType;

not

Trunc

Unary

Trunc(a: type): resultType;

Trunc

Round

Unary

Round(a: type): resultType;

Round

In

Set

In(a: type; b: type) : Boolean;

in

Equal

Comparison

Equal(a: type; b: type) : Boolean;

=

NotEqual

Comparison

NotEqual(a: type; b: type): Boolean;

<>

GreaterThan

Comparison

GreaterThan(a: type; b: type) Boolean;

>

GreaterThanOrEqual

Comparison

GreaterThanOrEqual(a: type; b: type): Boolean;

>=

LessThan

Comparison

LessThan(a: type; b: type): Boolean;

<

LessThanOrEqual

Comparison

LessThanOrEqual(a: type; b: type): Boolean;

<=

Add

Binary

Add(a: type; b: type): resultType;

+

Subtract

Binary

Subtract(a: type; b: type) : resultType;

-

Multiply

Binary

Multiply(a: type; b: type) : resultType;

*

Divide

Binary

Divide(a: type; b: type) : resultType;

/

IntDivide

Binary

IntDivide(a: type; b: type): resultType;

div

Modulus

Binary

Modulus(a: type; b: type): resultType;

mod

LeftShift

Binary

LeftShift(a: type; b: type): resultType;

shl

RightShift

Binary

RightShift(a: type; b: type): resultType;

shr

LogicalAnd

Binary

LogicalAnd(a: type; b: type): resultType;

and

LogicalOr

Binary

LogicalOr(a: type; b: type): resultType;

or

LogicalXor

Binary

LogicalXor(a: type; b: type): resultType;

xor

BitwiseAnd

Binary

BitwiseAnd(a: type; b: type): resultType;

and

BitwiseOr

Binary

BitwiseOr(a: type; b: type): resultType;

or

BitwiseXor

Binary

BitwiseXor(a: type; b: type): resultType;

xor


No operators other than those listed in the table may be defined on a record.

Overloaded operator methods cannot be referred to by name in source code. To access a specific operator method of a specific record, refer to: Code Example:OpOverloads_(Delphi). Operator identifiers are included for records in the language in the record's list of methods starting with the word "operator" (example: System.AnsiStringBase Methods). You can implement any of the above operators in your own records.

The compiler will use an operator for a record provided that:

  • For binary operators, one of the input parameters must be the record type.
  • For unary operators, either the input parameter or the return value must be the record type.
  • For a logical operator and a bitwise operator using the same symbol, the logical operator is used only when the operands are booleans. Since the type of record for this record operator is not a boolean, a logical operator will only be used when the other operand is a boolean.

No assumptions are made regarding the distributive or commutative properties of the operation. For binary operators, the first parameter is always the left operand, and the second parameter is always the right operand. Associativity is assumed to be left-to-right in the absence of explicit parentheses.

Resolution of operator methods is done over the union of accessible operators of the types used in the operation (note this includes inherited operators). For an operation involving two different types A and B, if type A has an implicit conversion to B, and B has an implicit conversion to A, an ambiguity will occur. Implicit conversions should be provided only where absolutely necessary, and reflexivity should be avoided. It is best to let type B implicitly convert itself to type A, and let type A have no knowledge of type B (or vice versa).

As a general rule, operators should not modify their operands. Instead, return a new value, constructed by performing the operation on the parameters.

Overloaded operators are used most often in records (that is, value types).

Note: Record helpers do not support operator overloading.

Declaring Operator Overloads

Operator overloads are declared within records, with the following syntax:

type
   typeName = record
       class operator conversionOp(a: type): resultType;
       class operator unaryOp(a: type): resultType;
       class operator comparisonOp(a: type; b: type): Boolean;
       class operator binaryOp(a: type; b: type): resultType;
   end;

Implementation of overloaded operators must also include the class operator syntax:

class operator typeName.conversionOp(a: type): resultType;
class operator typeName.unaryOp(a: type): resultType;
class operator typeName.comparisonOp(a: type; b: type): Boolean;
class operator typeName.binaryOp(a: type; b: type): resultType;

The following are some examples of overloaded operators:

type
   TMyRecord = record
     class operator Add(a, b: TMyRecord): TMyRecord;      // Addition of two operands of type TMyRecord
     class operator Subtract(a, b: TMyRecord): TMyRecord; // Subtraction of type TMyRecord
     class operator Implicit(a: Integer): TMyRecord;      // Implicit conversion of an Integer to type TMyRecord
     class operator Implicit(a: TMyRecord): Integer;      // Implicit conversion of TMyRecordto Integer
     class operator Explicit(a: Double): TMyRecord;       // Explicit conversion of a Double to TMyRecord
   end;

// Example implementation of Add
class operator TMyRecord.Add(a, b: TMyRecord): TMyRecord;
begin
   // ...
end;

var
x, y: TMyRecord;
begin
   x := 12;      // Implicit conversion from an Integer
   y := x + x;   // Calls TMyRecord.Add(a, b: TMyRecord): TMyRecord
   b := b + 100; // Calls TMyRecord.Add(b, TMyRecord.Implicit(100))
end;

See Also

Code Samples