Declaring a routine
procedure Swap(var A, B: Integer);
var T: Integer;
begin
T := A; A := B; B := T;
end;
function Max(A, B: Integer): Integer;
begin
if A > B then Result := A else Result := B; { Object Pascal: Result }
{ Max := A; ISO 7185 and Turbo Pascal: assign to the function name }
end;
A procedure does something; a function also gives back a value of
the type after the colon. The body is a block: declarations, then
begin … end;. A routine may declare other routines inside its
own declaration part (nested routines), which can use its variables and
parameters but are visible only inside it.
- The function result is set by assigning to the function’s name (the only way in ISO 7185 and Turbo Pascal), or to
Result(Delphi and Free Pascal in their Object Pascal modes; theresultmode switch), or withExit(Value). The function name on the right side of an assignment calls the function again, so recursion reads the result variable asResultand not by name. - A function may return any type except a file type. In ISO 7185 and in older Turbo Pascal a function cannot return a structured type, only a simple type or a pointer; Turbo Pascal also allows strings and records.
- A function that is called without its result being used is allowed with
{$X+}.
Parameters
| Kind | Written | Meaning |
|---|---|---|
| Value | (N: Integer) | A copy; changes do not reach the caller. |
| Variable | (var N: Integer) | The caller’s variable itself; the argument must be a variable of exactly that type. |
| Constant | (const S: string) | Read-only inside; passed by reference or copy as the compiler finds best (Turbo Pascal 7, Delphi, Free Pascal). constref (Free Pascal, and Delphi 2009 and later) forces a reference. |
| Output | (out N: Integer) | Like var but the old value is ignored, and managed types are cleared on entry (Delphi, Free Pascal). |
| Untyped | (var Buf), (const Buf) | Takes a variable of any type, which the routine treats as bytes (BlockRead, Move). |
| Open array | (const A: array of Integer) | Any array of that element type, indexed from 0 to High(A); a literal [1, 2, 3] is accepted. Turbo Pascal 7 and later; ISO 7185 level 1 has conformant arrays instead: (var A: array[Lo..Hi: Integer] of Real). |
| Array of const | (const Args: array of const) | A list of values of any type, passed as TVarRec records. |
| Procedural | (F: function(X: Real): Real) | A routine passed as an argument. ISO 7185 has it too, written function F(X: Real): Real in the parameter list. |
| Default value | (N: Integer = 10) | The argument may be left out. Delphi 4 and later, Free Pascal in Delphi and Object Pascal modes. Only value and const parameters, and the defaults must come last. |
Parameters of one type are grouped: (A, B: Integer; const S: string). A
parameter list separates groups with semicolons and the names within one with commas.
In a call, the arguments are separated by commas.
Directives
After the heading and its semicolon, words that say more about the routine may follow, each ended by a semicolon.
| Directive | Meaning |
|---|---|
forward | The body comes later in the same block. In a unit, the interface heading is the forward declaration. |
external | The routine is in another file or library: external 'lib.dll' name 'Func', external name 'c_func' (a linked object), external 'libc' index 4 (by ordinal). delayed loads the library on first use (Delphi). |
overload | Several routines of one name with different parameters. |
inline | Ask the compiler to put the body in at each call. In Turbo Pascal inline(…) is a statement with machine-code bytes. |
assembler | The body is assembly language only. |
cdecl stdcall pascal register safecall winapi cppdecl oldfpccall | The calling convention. See below. |
export | The routine is exported from a DLL or is called back from outside; far and near choose the call distance in 16-bit code. |
interrupt | A DOS interrupt handler, saving all registers (Turbo Pascal). |
varargs | The routine takes any extra arguments, like a C variadic function (with cdecl, external). |
deprecated platform experimental unimplemented library | Hint directives that make the compiler warn at use. |
local, nostackframe, noreturn, saveregisters, softfloat, far16, iocheck | Free Pascal’s own modifiers, described in its Reference guide. |
Calling conventions
| Name | Parameters passed | Cleared by | Used for |
|---|---|---|---|
register | the first three (Delphi 32-bit) in the processor registers, the rest on the stack, left to right | the routine | the default in Delphi and in Free Pascal on 32-bit Intel |
pascal | on the stack, left to right | the routine | old Windows and Mac APIs |
cdecl | on the stack, right to left | the caller | C libraries |
stdcall | on the stack, right to left | the routine | the Windows API |
safecall | as stdcall, with an HRESULT turned into an exception | the routine | COM |
winapi | the convention of the Windows API on the current platform (stdcall on 32-bit) | Windows API declarations |
The table gives the 32-bit Intel conventions; on 64-bit systems there is one native
convention and the names are accepted. {$CALLING name} in Free Pascal sets the default
for a section of code.
Overloading, default parameters
function Add(A, B: Integer): Integer; overload;
function Add(A, B: Double): Double; overload;
function Add(const S, T: string): string; overload;
procedure Log(const Msg: string; Level: Integer = 0);
Routines of one name may be overloaded with the overload directive on
each. The compiler picks by the number and types of the arguments, and reports an
ambiguity as an error. Free Pascal’s Reference guide describes the cases where the
directive can be left out.
Operator overloading
{ Free Pascal }
operator + (A, B: TVec) R: TVec;
begin
R.X := A.X + B.X; R.Y := A.Y + B.Y;
end;
{ Delphi (and Free Pascal advanced records) }
type TVec = record
X, Y: Double;
class operator Add(const A, B: TVec): TVec;
class operator Implicit(const V: Double): TVec;
end;
Free Pascal’s operator declares a global operator with a result name.
Delphi and Free Pascal (in advanced records) declare class operator members of a record or class
with names such as Add, Subtract, Multiply,
Divide, Equal, NotEqual, LessThan,
GreaterThan, GreaterThanOrEqual, LessThanOrEqual, Negative, Positive, LogicalNot,
Inc, Dec, In, Implicit, Explicit,
Round, Trunc, IntDivide, Modulus,
LeftShift, RightShift, LogicalAnd, LogicalOr,
LogicalXor, BitwiseAnd, BitwiseOr and BitwiseXor.
Implicit and Explicit define conversions to and from the type.
Nested, anonymous and recursive routines
- A nested routine is declared in the declaration part of another and can use its variables. A procedural variable may point at a nested routine only with
nestedprocvarsin Free Pascal. - An anonymous method (Delphi 2009 and later) is an unnamed routine written where a value is needed:
procedure begin … endorfunction(X: Integer): Integer begin … end. It captures the variables around it, extending their life as needed. It is assigned to areference totype. - A routine may call itself (recursion); the forward directive allows mutual recursion.
Methods
A routine that belongs to a class, object or record is a method and is declared in
the type, then defined with the type’s name in front: procedure TFoo.Bar;.
Constructors, destructors, virtual methods, class methods and the rest are on
Classes and objects.