Operator Overloading and Custom Managed Records

26.1 Operator Overloading (Records)

Supported operators: Add, Subtract, Multiply, Divide, IntDivide, Modulus, Negative, Positive, Inc, Dec, LogicalNot, LogicalAnd, LogicalOr, LogicalXor, BitwiseAnd/Or/Xor, LeftShift, RightShift, Equal, NotEqual, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual, Implicit, Explicit, In, Round, Trunc.

Operator overloading is supported on records, not on classes (classes only on mobile under the old ARC model).

type
  TMoney = record
  private
    FAmount: Currency;
    FCurrency: string;
  public
    constructor Create(AAmount: Currency; const ACurrency: string);
    class operator Add(const A, B: TMoney): TMoney;
    class operator Subtract(const A, B: TMoney): TMoney;
    class operator Multiply(const A: TMoney; Factor: Double): TMoney;
    class operator Equal(const A, B: TMoney): Boolean;
    class operator NotEqual(const A, B: TMoney): Boolean;
    class operator GreaterThan(const A, B: TMoney): Boolean;
    class operator Implicit(Value: Currency): TMoney;          // implicit conversion
    class operator Explicit(const Value: TMoney): Currency;    // explicit cast
    function ToString: string;
  end;

class operator TMoney.Add(const A, B: TMoney): TMoney;
begin
  if A.FCurrency <> B.FCurrency then raise EInvalidOpException.Create('Currency mismatch');
  Result := TMoney.Create(A.FAmount + B.FAmount, A.FCurrency);
end;

class operator TMoney.Implicit(Value: Currency): TMoney;
begin
  Result := TMoney.Create(Value, 'USD');
end;

var Price: TMoney := 19.99;          // Implicit
var Total := Price * 3 + TMoney.Create(5, 'USD');
var Raw := Currency(Total);          // Explicit

26.2 Custom Managed Records (Delphi 10.4+)

This enables RAII-style smart pointers, scoped locks, and auto-freeing wrappers:

type
  TSmartBuffer = record
  private
    FData: Pointer;
    FSize: NativeInt;
  public
    class operator Initialize(out Dest: TSmartBuffer);                  // called on declaration
    class operator Finalize(var Dest: TSmartBuffer);                    // called when going out of scope
    class operator Assign(var Dest: TSmartBuffer; const [ref] Src: TSmartBuffer);   // custom copy
    procedure Allocate(Size: NativeInt);
  end;

class operator TSmartBuffer.Initialize(out Dest: TSmartBuffer);
begin
  Dest.FData := nil;
  Dest.FSize := 0;
end;

class operator TSmartBuffer.Finalize(var Dest: TSmartBuffer);
begin
  FreeMem(Dest.FData);                  // RAII: automatic cleanup
end;

class operator TSmartBuffer.Assign(var Dest: TSmartBuffer; const [ref] Src: TSmartBuffer);
begin
  Dest.Allocate(Src.FSize);
  Move(Src.FData^, Dest.FData^, Src.FSize);   // deep copy
end;
type
  TAutoFree<T: class> = record
  private
    FObj: T;
  public
    class operator Initialize(out Dest: TAutoFree<T>);
    class operator Finalize(var Dest: TAutoFree<T>);
    property Obj: T read FObj write FObj;
  end;