Step 1 of 5 · Reading · ~2 min
Learn
Strings, Procedural Types, Variants
Pascal supports first-class function values via procedural types — types that name a procedure or function signature.
Everything below writes a function's return value as Result. That name only exists in Object Pascal dialects, so every program in this lesson (and the exercise) opens with {$mode objfpc}{$H+}; without it FPC 3.0.4 answers Identifier not found "Result".
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.
What Pascal does instead of a closure
A procedural-type variable stores an address and nothing else — it cannot capture a surrounding local. Delphi has anonymous methods (reference to function) that can; FPC only gained them in 3.3.x, and the 3.0.4 compiler behind this course rejects an inline function(x: integer): integer begin ... end outright with Illegal expression.
When a callback needs state, give the state a home and use a method pointer:
type
TScaler = class
public
Multiplier: integer;
function Apply(x: integer): integer;
end;
TIntMethod = function(x: integer): integer of object;
function TScaler.Apply(x: integer): integer;
begin
Result := x * Multiplier;
end;
Multiplier is the captured variable, held explicitly on the object; of object is what lets one value carry both the code and the instance it belongs to.
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…