DMarlon Studio

Lesson 15 · 15 of 20

Operator overloading · Pascal

Define +, * and conversions for your own types with advanced records in Free Pascal: a money type in cents that adds up like a number.

Pascal · Operator overloading in DMarlon Studio: the example's code and its output in the terminal

The `{$modeswitch advancedrecords}` directive lets a record have methods and operators, like a small class without Create or Free: it is a value that gets copied on assignment. TMoney stores the amount in whole cents (Int64) so money sums do not drag rounding errors along.

Each `class operator` teaches the compiler to use an operator with the type. + adds two TMoney values and * multiplies a TMoney by a whole quantity. They are implemented as functions: they receive the operands and return the result in Result.

The most interesting one is `:=`, the implicit conversion operator: it says how to turn a Double into a TMoney, rounding to cents. Thanks to it, coffee := 1.60 works, and in coffee * 2 + 3.25 the 3.25 is converted automatically so TMoney's + can be used.

ToString is an ordinary record method. `WriteStr` works like WriteLn but writes into a string, with the same :0:2 formatting, and needs no SysUtils unit. The result reads like a café bill: two coffees and a cake, 6.45 EUR.

Code · main.pas

program main;{$modeswitch advancedrecords}type  TMoney = record    Cents: Int64;  // whole cents: no rounding surprises    class operator :=(euros: Double): TMoney;    class operator +(a, b: TMoney): TMoney;    class operator *(a: TMoney; qty: Integer): TMoney;    function ToString: String;  end;class operator TMoney.:=(euros: Double): TMoney;begin  Result.Cents := Round(euros * 100);end;class operator TMoney.+(a, b: TMoney): TMoney;begin  Result.Cents := a.Cents + b.Cents;end;class operator TMoney.*(a: TMoney; qty: Integer): TMoney;begin  Result.Cents := a.Cents * qty;end;function TMoney.ToString: String;begin  WriteStr(Result, Cents / 100:0:2, ' EUR');  // like WriteLn, into a stringend;var coffee, bill: TMoney;begin  coffee := 1.60;             // := turns a Double into a TMoney  bill := coffee * 2 + 3.25;  // *, then + (3.25 is converted too)  WriteLn('Coffee: ', coffee.ToString, ' (', coffee.Cents, ' cents)');  WriteLn('2 coffees + 1 cake: ', bill.ToString);end.

Output · fpc main.pas && ./main

Coffee: 1.60 EUR (160 cents)
2 coffees + 1 cake: 6.45 EUR

Key points

  • {$modeswitch advancedrecords} gives records methods and operators.
  • class operator + defines what + does with your type.
  • class operator := defines an implicit conversion.
  • A record is a value: it is copied, never created or freed.
  • Store money as whole cents.

Exercise

Add class operator <(a, b: TMoney): Boolean and use it to print whether the bill is over 5 EUR; then add - to apply a 0.50 discount.