Operator Overloading in Delphi.NET

Operator overloading, or the ability to provide new implementations for built-in operators (such as '+', '-', '*' and '/') when the operands are user-defined types, is a new feature added to the Delphi language as of Delphi 8 (also known as Delphi.NET). This language feature is available in other languages such as C++ and C#. Those already familiar with how operator overloading is done in C# should have little trouble learning how operator overloading works in Delphi since the semantics are quite similar.

The point of operator overloading is to be able to provide a more intuitive way to use a class. For example, given a class TComplexNumber to represent complex numbers, it would be possible to define addition, subtraction, multiplication and division operations on complex numbers as follows:

    
TComplexNumber = class
strict private
  FReal: Double;
  FImaginary: Double;
public
  constructor Create(const Real, Imaginary: Double);
  function Add(const AValue: TComplexNumber): TComplexNumber;
  function Subtract(const AValue: TComplexNumber): TComplexNumber;
  function Multiply(const AValue: TComplexNumber): TComplexNumber;
  function Divide(const AValue: TComplexNumber): TComplexNumber;
  property Real: Double read FReal write FReal;
  property Imaginary: Double read FImaginary write FImaginary;
end;
    
  

Given the above class declaration, one could use the class to do complex number arithmetic as follows:

    
var
  A, B, C: TComplexNumber;
begin
  A := TComplexNumber.Create(9, 3);
  B := TComplexNumber.Create(7, 5);
  C := A.Add(B); // adds A and B, assigns result to C
  C := A.Subtract(B); // subtracts B from A, assigns result to C
  C := A.Multiply(B); // multiplies A and B, assigns result to C
  C := A.Divide(B); // divides A by B, assigns result to C
end.
    
  

This works but the way the code is written is not very intuitive. For example, it would be more intuitive to add A and B using the syntax 'A + B' rather than 'A.Add(B)'. In a similar fashion, it would be more intuitive to use the '-', '*' and '/' operators to perform subtraction, multiplication and division respectively, rather than having to use the 'Subtract', 'Multiply' and 'Divide' methods to do those same tasks.

This is where operator overloading comes in. Through operator overloading, it becomes possible for the author of the class to define implementations for operations wherein the class is an operand. Conversion, unary, comparison and binary operators can be overloaded. For a full list of overloadable operators and their corresponding declaration signatures, search for "Operator Overloads" in the Delphi.NET help.

Operator overloads in Delphi.NET are class (also known as "static") members and are declared using the operator keyword. The syntax is as follows (copied from the Delphi.NET help):

    
type
  typeName = [class | 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;
    
  

The 'class operator' syntax should be used in the implementation of the overloaded operators as well. For example (taken from the Delphi.NET help):

    
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;
    
  

Returning to the complex numbers example, to re-define the TComplexNumber class to use operator overloading instead of function calls to do arithmetic, it could be re-written as follows:

    
TComplexNumber = class
strict private
  FReal: Double;
  FImaginary: Double;
public
  constructor Create(const Real, Imaginary: Double);
  class operator Add(const X, Y: TComplexNumber): TComplexNumber;
  class operator Subtract(const X, Y: TComplexNumber): TComplexNumber;
  class operator Multiply(const X, Y: TComplexNumber): TComplexNumber;
  class operator Divide(const X, Y: TComplexNumber): TComplexNumber;
  property Real: Double read FReal write FReal;
  property Imaginary: Double read FImaginary write FImaginary;
end;
    
  

Having re-declared the class to use overloaded operators instead of functions, it then becomes possible to do complex number arithmetic as follows:

    
var
  A, B, C: TComplexNumber;
begin
  A := TComplexNumber.Create(9, 3);
  B := TComplexNumber.Create(7, 5);
  C := A + B; // adds A and B, assigns result to C
  C := A - B; // subtracts B from A, assigns result to C
  C := A * B; // multiplies A and B, assigns result to C
  C := A / B; // divides A by B, assigns result to C
end.
    
  

Using operator overloading, complex number arithmetic is now more intuitive and it makes the code clearer and easier to read.

Here is the full source for the TComplexNumber class as well as an example project showing its usage:

    
ComplexNumber.pas:
unit ComplexNumber;

interface

type
  TComplexNumber = class
  strict private
    FReal: Double;
    FImaginary: Double;
  strict protected
    function Conjugate: TComplexNumber;
  public
    constructor Create(const Real, Imaginary: Double);
    class operator Add(const X, Y: TComplexNumber): TComplexNumber;
    class operator Subtract(const X, Y: TComplexNumber): TComplexNumber;
    class operator Multiply(const X, Y: TComplexNumber): TComplexNumber;
    class operator Divide(const X, Y: TComplexNumber): TComplexNumber;
    function ToString: string; override;
    property Real: Double read FReal write FReal;
    property Imaginary: Double read FImaginary write FImaginary;
  end;

implementation

uses
  SysUtils;

{ TComplexNumber }

function TComplexNumber.Conjugate: TComplexNumber;
begin
  Result := TComplexNumber.Create(FReal, FImaginary * -1);
end;

constructor TComplexNumber.Create(const Real, Imaginary: Double);
begin
  inherited Create;
  FReal := Real;
  FImaginary := Imaginary;
end;

class operator TComplexNumber.Add(const X,
  Y: TComplexNumber): TComplexNumber;
begin
  Result := TComplexNumber.Create(X.Real + Y.Real, X.Imaginary + Y.Imaginary);
end;

class operator TComplexNumber.Subtract(const X,
  Y: TComplexNumber): TComplexNumber;
begin
  Result := TComplexNumber.Create(X.Real - Y.Real, X.Imaginary - Y.Imaginary);
end;

class operator TComplexNumber.Multiply(const X,
  Y: TComplexNumber): TComplexNumber;
begin
  Result := TComplexNumber.Create((X.Real * Y.Real - X.Imaginary * Y.Imaginary),
                                  (X.Real * Y.Imaginary + X.Imaginary * Y.Real));
end;

class operator TComplexNumber.Divide(const X,
  Y: TComplexNumber): TComplexNumber;
begin
  Result := TComplexNumber.Create((X * Y.Conjugate).Real / (Y * Y.Conjugate).Real,
                                  (X * Y.Conjugate).Imaginary / (Y * Y.Conjugate).Real);
end;

function TComplexNumber.ToString: string;
begin
  if (Imaginary > 0) then
    Result := Format('%f+%fi', [FReal, FImaginary])
  else
    Result := Format('%f%fi', [FReal, FImaginary]);
end;

end.

Project1.dpr:
program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ComplexNumber in 'ComplexNumber.pas';

var
  A, B: TComplexNumber;

begin
  A := TComplexNumber.Create(9, 3);
  B := TComplexNumber.Create(7, 5);
  WriteLn(Format('A = (%s), B = (%s)', [A, B]));
  WriteLn(Format('A + B = (%s)', [A + B]));
  WriteLn(Format('A - B = (%s)', [A - B]));
  WriteLn(Format('A * B = (%s)', [A * B]));
  WriteLn(Format('A / B = (%s)', [A / B]));
end.
    
  

This should produce the following output:

[d:\source\delphi.net\code\tcomplexnumber]Project1.exe
A = (9.00+3.00i), B = (7.00+5.00i)
A + B = (16.00+8.00i)
A - B = (2.00-2.00i)
A * B = (48.00+66.00i)
A / B = (1.05-0.32i)

[d:\source\delphi.net\code\tcomplexnumber]
    

Last updated on 2004-05-11.