Delphi operator overloading

Operator overloading is a feature of Delphi, introduced in version 7. It's use is restricted to records, unless you are using Delphi .NET (support for classes too). Not until recently I found a practical usage for them.

One application I am working on makes use of custom colours. For example, it displays system messages in a colour of choice. To select the colour a dialog is used, which returns a TColor. To show the actual messages, a webbrowser component is used, which needs an HTML colour code. I decided to replace my conversion function with a custom colour record and make use of Delphi's operator overloading capabilities. Basically, I made a record that is able to convert between a TColor and a string (the HTML version). Let me show you how.

Basic setup

Start with a new type definition, for example:

type
  ThpColor = record
    Color: TColor;
    class operator Equal(ALeftOp, ARightOp: ThpColor): Boolean;
    class operator NotEqual(ALeftOp, ARightOp: ThpColor): Boolean;
    class operator Implicit(AValue: ThpColor): string;
    class operator Implicit(AValue: ThpColor): TColor;
    class operator Implicit(AValue: string): ThpColor;
    class operator Implicit(AValue: TColor): ThpColor;
  end;

I'll explain what each part is for step by step.

The type

The type I chose to work with is a TColor. It's defined first as a property called Color. This will hold the current value.

Equality check

The next two lines define the equal (=) and not equal (<>) operators. Each function has two parameters, one for the left operand (ALeftOp) of the expression, and one for the right (ARightOp). They are implemented in a very straightforward manner, because I use a simple type:

class operator ThpColor.Equal(ALeftOp, ARightOp: ThpColor): Boolean;
begin
  Result := ALeftOp.Color = ARightOp.Color;
end;

class operator ThpColor.NotEqual(ALeftOp, ARightOp: ThpColor): Boolean;
begin
  Result := ALeftOp.Color <> ARightOp.Color;
end;

Assign your type to another type

If you want to be able to assign your type to something else, you will have to use the Implicit operator overload function with your type as the only parameter. The result of the function must be of the type you want to assign it to. The two functions are implemented to return a TColor (simply returning our internal type) or a string (requires some formatting).

class operator ThpColor.Implicit(AValue: ThpColor): TColor;
begin
  Result := AValue.Color;
end;

class operator ThpColor.Implicit(AValue: ThpColor): string;
begin
  Result := Format('#%s%s%s', [
    IntToHex(GetRValue(AValue.Color), 2),
    IntToHex(GetGValue(AValue.Color), 2),
    IntToHex(GetBValue(AValue.Color), 2)]);
end;

Assign another type to your type

If you want to assign other types to yours, then you will have to use the Implicit operator overload function too. The parameter has to be of the type you want to copy from, and the result has to be of your type. The TColor conversion is a simple assignment, whereas the string conversion requires some parsing.

class operator ThpColor.Implicit(AValue: TColor): ThpColor;
begin
  Result.Color := AValue;
end;

class operator ThpColor.Implicit(AValue: string): ThpColor;
var
  R, G, B: Byte;
begin
  if Pos('#', AValue) = 1 then
    Delete(AValue, 1, 1);

  R := StrToIntDef('$' + Copy(AValue, 1, 2), 0);
  G := StrToIntDef('$' + Copy(AValue, 3, 2), 0);
  B := StrToIntDef('$' + Copy(AValue, 5, 2), 0);

  Result.Color := RGB(R, G, B);
end;

In the above string conversion, we check if it starts with a hash-tag and remove it when present. This will allow us to accept #RRGGBB as well as RRGGBB formats.

Some tests

To test if the record we just made does what we want it to do, try the following lines of code (I used a console application for testing).

var
  hpColor1, hpColor2: ThpColor;
  color1: string;
  color2: TColor;
begin
  hpColor1 := clRed;           // assign a TColor to a ThpColor
  hpColor2 := '#ff0000';       // assign a string to a ThpColor
  if hpColor1 = hpColor2 then  // compare two ThpColor
    Writeln('Equal');

  color1 := hpColor1;          // assign a ThpColor to a string
  Writeln(color1);

  color2 := hpColor2;          // assign a ThpColor to a TColor
  if color2 <> hpColor1 then
    Writeln('NotEqual');

  Readln;
end.

You can step through the code to see what functions are called. In this example it is pretty straightforward, but if you are using multiple conversions on a single line it can get messy real quick.

Download the file

Download the unit with the type definition and comments: hpColor-1.00.zip (1Kb)

Additional reading

Operator Overloading (Delphi) from the Embarcadero wiki shows you the available operator overloading functions.