Skip to content
Procedural Types and Callbacks
step 1/5

Reading — step 1 of 5

Learn

~2 min readStrings, Procedural Types, Variants

Pascal supports first-class function values via procedural types — types that name a procedure or function signature.

Declaring

type
    TIntFunc = function(x: integer): integer;
    TIntProc = procedure(x: integer);
    TBinOp = function(a, b: integer): integer;

Using

function Square(x: integer): integer;
begin
    Result := x * x;
end;

function Add(a, b: integer): integer;
begin
    Result := a + b;
end;

var
    f: TIntFunc;
    op: TBinOp;
begin
    f := @Square;            { take address }
    WriteLn(f(7));            { 49 }

    op := @Add;
    WriteLn(op(3, 4));        { 7 }
end.

The @ is required to take the address of a function (FPC and Delphi both work this way).

Higher-order patterns

Map with a callback:

function MapInts(a: array of integer; f: TIntFunc): TIntArray;
var i: integer;
begin
    SetLength(Result, Length(a));
    for i := 0 to High(a) do
        Result[i] := f(a[i]);
end;

var
    nums, squared: TIntArray;
begin
    nums := [1, 2, 3, 4, 5];
    squared := MapInts(nums, @Square);
    { squared = [1, 4, 9, 16, 25] }
end.

Method pointers (procedure of object)

Point to a method on an instance — the variable carries both the function and its self:

type
    TButtonClick = procedure(Sender: TObject) of object;

    TForm = class
    public
        OnClick: TButtonClick;
    end;

The of object makes the type include a hidden Self pointer. This is how Delphi's event handlers work — every component property like OnClick is a procedure of object.

Anonymous methods (Delphi-style closures)

FPC 2.7+ supports closures with the Anonymous keyword (still less common than in other languages):

var
    multiplier: integer;
    f: TIntFunc;
begin
    multiplier := 5;
    f := function(x: integer): integer
         begin
             Result := x * multiplier;
         end;
    WriteLn(f(7));            { 35 }
end.

In FPC, you may need {$mode objfpc}{$modeswitch advancedrecords} directive flags.

Use cases

  • Sorting with custom comparators
  • Event-driven UI (OnClick, OnChange, OnKeyDown)
  • Strategy pattern: pass behavior as a value
  • Decoupling: caller provides callback, library doesn't depend on caller
  • Plugin systems

Most FPC code uses procedural types alongside classes — methods for state, plain procedures for stateless callbacks.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…