DMarlon Studio

Lesson 6 · 6 of 20

Interfaces · Pascal

Define Object Pascal interfaces, implement them in unrelated classes and let reference counting free the objects for you.

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

An interface is a contract: a list of methods with no data and no code. ITax only says there is an Apply(net) function. By convention, its name starts with I.

The TVat (mainland Spain VAT, 21 %) and TIgic (Canary Islands tax, 7 %) classes implement the interface: they name it after the parent class, class(TInterfacedObject, ITax), and write their own Apply. They are not related to each other; all they share is the contract. A class inherits from a single parent but can implement several interfaces.

Quote takes an ITax parameter, so it accepts any object that honours the contract, whatever its class. This is how you write code that does not depend on concrete classes.

`TInterfacedObject` brings reference counting: every interface variable or parameter pointing at the object adds one, and when the count drops back to zero the object frees itself. That is why Quote('Madrid', TVat.Create, 250) needs no Free: the object goes away when the call ends. The tax variable keeps its object alive until tax := nil.

The golden rule: an object handled through an interface is never released with Free, nor kept in a class variable at the same time. If you need Supports or the as operator with interfaces, give them a GUID in square brackets.

Code · main.pas

program main;type  ITax = interface    function Apply(net: Double): Double;  end;  TVat = class(TInterfacedObject, ITax)    function Apply(net: Double): Double;  end;  TIgic = class(TInterfacedObject, ITax)    function Apply(net: Double): Double;  end;function TVat.Apply(net: Double): Double;begin  Result := net * 1.21;  // mainland Spainend;function TIgic.Apply(net: Double): Double;begin  Result := net * 1.07;  // Canary Islandsend;procedure Quote(const region: String; tax: ITax; net: Double);begin  WriteLn(region:9, ': ', net:7:2, ' net -> ', tax.Apply(net):7:2, ' EUR');end;var tax: ITax;begin  Quote('Madrid', TVat.Create, 250);     // the object is freed after the call  Quote('Tenerife', TIgic.Create, 250);  tax := TIgic.Create;                   // kept alive while tax refers to it  Quote('La Palma', tax, 19.99);  tax := nil;                            // last reference gone: freed hereend.

Output · fpc main.pas && ./main

   Madrid:  250.00 net ->  302.50 EUR
 Tenerife:  250.00 net ->  267.50 EUR
 La Palma:   19.99 net ->   21.39 EUR

Key points

  • An interface is a list of methods a class promises to provide.
  • A class can implement several interfaces.
  • An interface parameter accepts any class that implements it.
  • With TInterfacedObject, an object frees itself when no references remain.
  • Do not mix Free with interface-managed objects.

Exercise

Create TExempt = class(TInterfacedObject, ITax) for exports, whose Apply returns the net amount untaxed, and add a Quote('Export', TExempt.Create, 250) line.