Usage of Interfaces in Free Pascal

 

Basic Concept

Interfaces can set boundaries between your code and third parties (such as libraries and APIs). By wrapping third-party code into custom classes, you can restrict access and avoid exposing implementation details to the rest of the system. Interfaces can also define the behavior of yet-to-be-written code, allowing development to continue without impediments.

Data Abstraction

Interfaces are not only meant to provide getters and setters for private variables, but also to expose abstractions. A class shouldn’t expose its variables to the outside world; it should provide abstract interfaces so that the user can manipulate the essence of the data without knowing its implementation.

Dependency Inversion

Interfaces are essential tools for the Open/Closed and Dependency Inversion principles. They can isolate the system from volatile concrete details. For example, instead of depending directly on a concrete class TokyoStockExchange, one should create a StockExchange interface. This isolates the code from specific implementation details.

The usage of interfaces enhances testability by allowing the creation of "Test Doubles" or "Mock Objects." By depending on an interface, it’s possible to swap a heavy component (like a real database) for a light testing implementation

How it works in Java

Based on Java SE (Java Language Specification), an interface is a type of reference that defines a contract of behavior. It can’t be instantiate directly. Its main object is grant that non-related classes share ****common behaviors without the need to inherit from the same abstract class.

An interface can contain method declarations, constants (fields), nested classes and other interfaces. Typically, it declares abstract methods (without body/implementation) leaving the responsibility of implementation to the classes which will inherit.

Check out below how an interface is defined in Java, it is very similar to creating a new class:

`public interface OperateCar {

// constant declarations, if any

// method signatures

// An enum with values RIGHT, LEFT int turn(Direction direction, double radius, double startSpeed, double endSpeed); int changeLanes(Direction direction, double startSpeed, double endSpeed); int signalTurn(Direction direction, boolean signalOn); int getRadarFront(double distanceToCar, double speedOfCar); int getRadarRear(double distanceToCar, double speedOfCar); ...... // more method signatures }`

Note that the method signatures have no braces and are terminated with a semicolon.

To use an interface, you write a class that implements the interface. When an instantiable class implements an interface, it provides a method body for each of the methods declared in the interface. For example,

`public class OperateBMW760i implements OperateCar {

// the OperateCar method signatures, with implementation --
// for example:
public int signalTurn(Direction direction, boolean signalOn) {
   // code to turn BMW's LEFT turn indicator lights on
   // code to turn BMW's LEFT turn indicator lights off
   // code to turn BMW's RIGHT turn indicator lights on
   // code to turn BMW's RIGHT turn indicator lights off
}

// other members, as needed -- for example, helper classes not 
// visible to clients of the interface

}`

In the robotic car example above, it is the automobile manufacturers who will implement the interface. Chevrolet's implementation will be substantially different from that of Toyota, of course, but both manufacturers will adhere to the same interface. The guidance manufacturers, who are the clients of the interface, will build systems that use GPS data on a car's location, digital street maps, and traffic data to drive the car. In so doing, the guidance systems will invoke the interface methods: turn, change lanes, brake, accelerate, and so forth.

How it works in Free Pascal (Lazarus)

In Object Pascal, interfaces are primarily used as a way to achieve multiple polymorphism, since the language does not support multiple inheritance between classes. Unlike classes, interfaces do not carry state or implementation details, they define what must be done, not how it is done.

An interface in Free Pascal defines a contract that a class can implement. A single class can implement multiple interfaces, allowing it to expose different behaviors to different parts of the system without sharing a common base class.

Interfaces are defined in a way very similar to abstract classes, but with a few important differences: All methods are implicitly public; No implementation or fields are allowed; Properties are allowed, as long as they are backed by methods. Example of an interface definition:

type
  TMyInterface = interface
    function GetX: TData;
    procedure SetX(AValue: TData);
    property X: TData read GetX write SetX;
  end;

To use an interface, a class must explicitly implement it and provide concrete implementations for all declared methods:

type
  TMyClass = class(TInterfacedObject, TMyInterface)
    function GetX: TData;
    procedure SetX(AValue: TData);
  end;

TInterfacedObject already implements the required low-level interface mechanisms, so in most cases you don’t need to handle them manually.

Using interfaces as access points

An interface is not an object by itself — it is a view or access point to an object. The same object can be accessed through multiple interfaces, each one exposing a specific subset of behavior.

This makes interfaces ideal for defining boundaries between layers, hiding implementation details, and depending on abstractions instead of concrete classes.

Casting a class instance to one of its interfaces is straightforward:

MyInterface := MyClass;

If an interface inherits from another interface, it is memory-compatible with its parent and can be used interchangeably where appropriate.

Lifetime management and reference counting

Interfaces in Object Pascal are reference-counted. When an interface reference is assigned, its reference count is incremented; when it goes out of scope, the count is decremented. Once the count reaches zero, the underlying object is automatically destroyed.

This means you must not manually destroy objects that are managed through interfaces:

procedure SomeProc;
var
  MyClass: TMyClass;
  MyInterface: TMyInterface;
begin
  MyClass := TMyClass.Create;
  MyInterface := MyClass;
  // Object is destroyed automatically when MyInterface goes out of scope
end;

In Free Pascal, interfaces provide:

  • Multiple polymorphism without multiple inheritance
  • Strong abstraction boundaries
  • Automatic lifetime management via reference counting

References

Comments