Procedures and functions--referred to collectively as routines--are self-contained statement blocks that can be called from different locations in a program. A function is a routine that returns a value when it executes. A procedure is a routine that does not return a value.

Function calls, because they return a value, can be used as expressions in assignments and operations. For example,
I := SomeFunction(X);

calls SomeFunction and assigns the result to I. Function calls cannot appear on the left side of an assignment statement.

Both function and procedure calls can be used as complete statements. For example,
DoSomething;

calls the DoSomething routine; if DoSomething is a function, its return value is discarded.

Procedures and functions can call themselves recursively.
Declaring procedures and functions

When you declare a procedure or function, you specify its name, the number and type of parameters it takes, and, in the case of a function, the type of its return value; this part of the declaration is sometimes called the prototype, heading, or header. Then you write a block of code that executes whenever the procedure or function is called; this part is sometimes called the routine's body or block.

The standard procedure Exit can occur within the body of any procedure or function. Exit halts execution of the routine where it occurs and immediately passes program control back to the point from which the routine was called.
Procedure declarations

A procedure declaration has the form

procedure procedureName(parameterList); directives;
localDeclarations;
begin
statements
end;


where procedureName is any valid identifier, statements is a sequence of statements that execute when the procedure is called, and (parameterList), directives;, and localDeclarations; are optional.

For information about the parameterList, see "Parameters".
For information about directives, see "Calling conventions", "Forward and interface declarations", "External declarations", and "Overloading procedures and functions". If you include more than one directive, separate them with semicolons.
For information about localDeclarations, which declares local identifiers, see "Local declarations".


Here is an example of a procedure declaration:
procedure NumString(N: Integer; var S: string);
var
V: Integer;
begin
V := Abs(N);
S := '';
repeat
S := Chr(V mod 10 + Ord('0')) + S;
V := V div 10;
until V = 0;
if N < 0 then S := '-' + S;
end;

Given this declaration, you can call the NumString procedure like this:
NumString(17, MyString);

This procedure call assigns the value "17" to MyString (which must be a string variable).

Within a procedure's statement block, you can use variables and other identifiers declared in the localDeclarations part of the procedure. You can also use the parameter names from the parameter list (like N and S in the example above); the parameter list defines a set of local variables, so don't try to redeclare the parameter names in the localDeclarations section. Finally, you can use any identifiers within whose scope the procedure declaration falls.
Function declarations

A function declaration is like a procedure declaration except that it specifies a return type and a return value. Function declarations have the form

function functionName(parameterList): returnType; directives;
localDeclarations;
begin
statements
end;


where functionName is any valid identifier, returnType is any type, statements is a sequence of statements that execute when the function is called, and (parameterList), directives;, and localDeclarations; are optional.

For information about the parameterList, see "Parameters".
For information about directives, see "Calling conventions", "Forward and interface declarations", "External declarations", and "Overloading procedures and functions". If you include more than one directive, separate them with semicolons.
For information about localDeclarations, which declares local identifiers, see "Local declarations".


The function's statement block is governed by the same rules that apply to procedures. Within the statement block, you can use variables and other identifiers declared in the localDeclarations part of the function, parameter names from the parameter list, and any identifiers within whose scope the function declaration falls. In addition, the function name itself acts as a special variable that holds the function's return value, as does the predefined variable Result.

For example,
function WF: Integer;
begin
WF := 17;
end;

defines a constant function called WF that takes no parameters and always returns the integer value 17. This declaration is equivalent to
function WF: Integer;
begin
Result := 17;
end;

Here is a more complicated function declaration:
function Max(A: array of Real; N: Integer): Real;
var
X: Real;
I: Integer;
begin
X := A[0];
for I := 1 to N - 1 do
if X < A[I] then X := A[I];
Max := X;
end;

You can assign a value to Result or to the function name repeatedly within a statement block, as long as you assign only values that match the declared return type. When execution of the function terminates, whatever value was last assigned to Result or to the function name becomes the function's return value. For example,
function Power(X: Real; Y: Integer): Real;
var
I: Integer;
begin
Result := 1.0;
I := Y;
while I > 0 do
begin
if Odd(I) then Result := Result * X;
I := I div 2;
X := Sqr(X);
end;
end;

Result and the function name always represent the same value. Hence
function MyFunction: Integer;
begin
MyFunction := 5;
Result := Result * 2;
MyFunction := Result + 1;
end;

returns the value 11. But Result is not completely interchangeable with the function name. When the function name appears on the left side of an assignment statement, the compiler assumes that it is being used (like Result) to track the return value; when the function name appears anywhere else in the statement block, the compiler interprets it as a recursive call to the function itself. Result, on the other hand, can be used as a variable in operations, typecasts, set constructors, indexes, and calls to other routines.

Result is implicitly declared in every function, so do not try to redeclare it.

If execution terminates without an assignment being made to Result or the function name, then the function's return value is undefined.
Calling conventions

When you declare a procedure or function, you can specify a calling convention using one of the directives register, pascal, cdecl, stdcall, and safecall. For example,
function MyFunction(X, Y: Real): Real; cdecl;
...

Calling conventions determine the order in which parameters are passed to the routine. They also affect the removal of parameters from the stack, the use of registers for passing parameters, and error and exception handling. The default calling convention is register.

The register and pascal conventions pass parameters from left to right; that is, the leftmost parameter is evaluated and passed first and the rightmost parameter is evaluated and passed last. The cdecl, stdcall, and safecall conventions pass parameters from right to left.
For all conventions except cdecl, the procedure or function removes parameters from the stack upon returning. With the cdecl convention, the caller removes parameters from the stack when the call returns.
The register convention uses up to three CPU registers to pass parameters, while the other conventions pass all parameters on the stack.
The safecall convention implements COM error and exception handling.


The table below summarizes calling conventions.


Table 6.1 Calling conventions
Directive
Parameter order
Clean-up
Passes parameters in registers?

register
Left-to-right
Routine
Yes

pascal
Left-to-right
Routine
No

cdecl
Right-to-left
Caller
No

stdcall
Right-to-left
Routine
No

safecall
Right-to-left
Routine
No



The default register convention is the most efficient, since it usually avoids creation of a stack frame. (Access methods for published properties must use register.) The cdecl convention is useful when you call functions from DLLs written in C or C++, while stdcall and safecall are used for Windows API calls. The safecall convention must be used for declaring dual-interface methods (see "Object interfaces"). The pascal convention is maintained for backward compatibility. For more information on calling conventions, see Chapter 12, "Program control."

The directives near, far, and export refer to calling conventions in 16-bit Windows programming. They have no effect in 32-bit applications and are maintained for backward compatibility only.
Forward and interface declarations

The forward directive replaces the block, including local variable declarations and statements, in a procedure or function declaration. For example,
function Calculate(X, Y: Integer): Real; forward;

declares a function called Calculate. Somewhere after the forward declaration, the routine must be redeclared in a defining declaration that includes a block. The defining declaration for Calculate might look like this:
function Calculate;
... { declarations }
begin
... { statement block }
end;

Ordinarily, a defining declaration does not have to repeat the routine's parameter list or return type, but if it does repeat them, they must match those in the forward declaration exactly (except that default parameters can be omitted). If the forward declaration specifies an overloaded procedure or function (see "Overloading procedures and functions"), then the defining declaration must repeat the parameter list.

Between a forward declaration and its defining declaration, you can place nothing except other declarations. The defining declaration can be an external or assembler declaration, but it cannot be another forward declaration.

The purpose of a forward declaration is to extend the scope of a procedure or function identifier to an earlier point in the source code. This allows other procedures and functions to call the forward-declared routine before it is actually defined. Besides letting you organize your code more flexibly, forward declarations are sometimes necessary for mutual recursions.

The forward directive is not allowed in the interface section of a unit. Procedure and function headers in the interface section, however, behave like forward declarations and must have defining declarations in the implementation section. A routine declared in the interface section is available from anywhere else in the unit and from any other unit or program that uses the unit where it is declared.
External declarations

The external directive, which replaces the block in a procedure or function declaration, allows you to call procedures and functions that are compiled separately from your program.
Linking to .OBJ files

To call routines from a separately compiled .OBJ file, first link the .OBJ file to your application using the $L (or $LINK) compiler directive. For example,
{$L BLOCK.OBJ}

links BLOCK.OBJ into the program or unit in which it occurs. Next, declare the functions and procedures that you want to call:
procedure MoveWord(var Source, Dest; Count: Integer); external;
procedure FillWord(var Dest; Data: Integer; Count: Integer); external;

Now you can call the MoveWord and FillWord routines from BLOCK.OBJ.

Declarations like the ones above are frequently used to access external routines written in assembly language. You can also place assembly-language routines directly in your Object Pascal source code; for more information, see "Inline assembler code."
Importing functions from DLLs

To import routines from a dynamic-link library, attach a directive of the form

external stringConstant;


to the end of a normal procedure or function header, where stringConstant is the name of the .DLL file in single quotation marks. For example,
function SomeFunction(S: string): string; external 'strlib.dll';

imports a function called SomeFunction from STRLIB.DLL.

You can import a routine under a different name from the one it has in the DLL. If you do this, specify the original name in the external directive:

external stringConstant1 name stringConstant2;


where the first stringConstant gives the name of the .DLL file and the second stringConstant is the routine's original name. For example, the following declaration imports a function from USER32.DLL (part of the Windows API).
function MessageBox(HWnd: Integer; Text, Caption: PChar; Flags: Integer): Integer;
stdcall; external 'user32.dll' name 'MessageBoxA';

The function's original name is MessageBoxA, but it is imported as MessageBox.

Instead of a name, you can use a number to identify the routine you want to import:

external stringConstant index integerConstant;


where integerConstant is the routine's index in the DLL export table.

In your importing declaration, be sure to match the exact spelling and case of the routine's name. Later, when you call the imported routine, the name is case-insensitive.

For more information about DLLs, see "Dynamic-link libraries and packages."
Overloading procedures and functions

You can declare more than one routine in the same scope with the same name. This is called overloading. Overloaded routines must be declared with the overload directive and must have distinguishing parameter lists. For example, consider the declarations
function Divide(X, Y: Real): Real; overload;
begin
Result := X/Y;
end;

function Divide(X, Y: Integer): Integer; overload;
begin
Result := X div Y;
end;

These declarations create two functions, both called Divide, that take parameters of different types. When you call Divide, the compiler determines which function to invoke by looking at the actual parameters passed in the call. For example, Divide(6.0, 3.0) calls the first Divide function, because its arguments are real-valued.

You can pass to an overloaded routine parameters that are not identical in type with those in any of the routine's declarations, but that are assignment-compatible with the parameters in more than one declaration. This happens most frequently when a routine is overloaded with different integer types or different real types--for example,
procedure Store(X: Longint); overload;
procedure Store(X: Shortint); overload;

In these cases, when it is possible to do so without ambiguity, the compiler invokes the routine whose parameters are of the type with the smallest range that accommodates the actual parameters in the call. (Remember that real-valued constant expressions are always of type Extended.)

Overloaded routines must be distinguished by the number of parameters they take or the types of their parameters. Hence the following pair of declarations causes a compilation error.
function Cap(S: string): string; overload;
...
procedure Cap(var Str: string); overload;
...

But the declarations
function Func(X: Real; Y: Integer): Real; overload;
...
function Func(X: Integer; Y: Real): Real; overload;
...

are legal.

When an overloaded routine is declared in a forward or interface declaration, the defining declaration must repeat the routine's parameter list.

If you use default parameters in overloaded routines, be careful of ambiguous parameter signatures. For more information, see "Default parameters and overloaded routines".

You can limit the potential effects of overloading by qualifying a routine's name when you call it. For example, Unit1.MyProcedure(X, Y) can call only routines declared in Unit1; if no routine in Unit1 matches the name and parameter list in the call, an error results.

For information about distributing overloaded methods in a class hierarchy, see "Overloading methods". For information about exporting overloaded routines from a DLL, see "The exports clause".
Local declarations

The body of a function or procedure often begins with declarations of local variables used in the routine's statement block. These declarations can also include constants, types, and other routines. The scope of a local identifier is limited to the routine where it is declared.
Nested routines

Functions and procedures sometimes contain other functions and procedures within the local-declarations section of their blocks. For example, the following declaration of a procedure called DoSomething contains a nested procedure.
procedure DoSomething(S: string);
var
X, Y: Integer;

procedure NestedProc(S: string);
begin
...
end;

begin
...
NestedProc(S);
...
end;

The scope of a nested routine is limited to the procedure or function in which it is declared. In our example, NestedProc can be called only within DoSomething.

For real examples of nested routines, look at the DateTimeToString procedure, the ScanDate function, and other routines in the SysUtils unit.
Parameters

Most procedure and function headers include a parameter list. For example, in the header
function Power(X: Real; Y: Integer): Real;

the parameter list is (X: Real; Y: Integer).

A parameter list is a sequence of parameter declarations separated by semicolons and enclosed in parentheses. Each declaration is a comma-delimited series of parameter names, followed in most cases by a colon and a type identifier, and in some cases by the = symbol and a default value. Parameter names must be valid identifiers. Any declaration can be preceded by one of the reserved words var, const, and out. Examples:
(X, Y: Real)
(var S: string; X: Integer)
(HWnd: Integer; Text, Caption: PChar; Flags: Integer)
(const P; I: Integer)

The parameter list specifies the number, order, and type of parameters that must be passed to the routine when it is called. If a routine does not take any parameters, omit the identifier list and the parentheses in its declaration:
procedure UpdateRecords;
begin
...
end;

Within the procedure or function body, the parameter names (X and Y in the first example above) can be used as local variables. Do not redeclare the parameter names in the local declarations section of the procedure or function body.
Parameter semantics

Parameters are categorized in several ways:

Every parameter is classified as value, variable, constant, or out. Value parameters are the default; the reserved words var, const, and out indicate variable, constant, and out parameters, respectively.
Value parameters are always typed, while constant, variable, and out parameters can be either typed or untyped.
Special rules apply to array parameters. See "Array parameters".


Files and instances of structured types that contain files can be passed only as variable (var) parameters.
Value and variable parameters

Most parameters are either value parameters (the default) or variable (var) parameters. Value parameters are passed by value, while variable parameters are passed by reference. To see what this means, consider the following functions.
function DoubleByValue(X: Integer): Integer; // X is a value parameter
begin
X := X * 2;
Result := X;
end;

function DoubleByRef(var X: Integer): Integer; // X is a variable parameter
begin
X := X * 2;
Result := X;
end;

These functions return the same result, but only the second one--DoubleByRef--can change the value of a variable passed to it. Suppose we call the functions like this:
var
I, J, V, W: Integer;
begin
I := 4;
V := 4;
J := DoubleByValue(I); // J = 8, I = 4
W := DoubleByRef(V); // W = 8, V = 8
end;

After this code executes, the variable I, which was passed to DoubleByValue, has the same value we initially assigned to it. But the variable V, which was passed to DoubleByRef, has a different value.

A value parameter acts like a local variable that gets initialized to the value passed in the procedure or function call. If you pass a variable as a value parameter, the procedure or function creates a copy of it; changes made to the copy have no effect on the original variable and are lost when program execution returns to the caller.

A variable parameter, on the other hand, acts like a pointer rather than a copy. Changes made to the parameter within the body of a function or procedure persist after program execution returns to the caller and the parameter name itself has gone out of scope.

Even if the same variable is passed in two or more var parameters, no copies are made. This is illustrated in the following example.
procedure AddOne(var X, Y: Integer);
begin
X := X + 1;
Y := Y + 1;
end;

var I: Integer;
begin
I := 1;
AddOne(I, I);
end;

After this code executes, the value of I is 3.

If a routine's declaration specifies a var parameter, you must pass an assignable expression--that is, a variable, typed constant (in the {$J+} state), dereferenced pointer, field, or indexed variable--to the routine when you call it. To use our previous examples, DoubleByRef(7) produces an error, although DoubleByValue(7) is legal.

Indexes and pointer dereferences passed in var parameters--for example, DoubleByRef(MyArray[I])--are evaluated once, before execution of the routine.
Constant parameters

A constant (const) parameter is like a local constant or read-only variable. Constant parameters are similar to value parameters, except that you can't assign a value to a constant parameter within the body of a procedure or function, nor can you pass one as a var parameter to another routine. (But when you pass an object reference as a constant parameter, you can still modify the object's properties.)

Using const allows the compiler to optimize code for structured- and string-type parameters. It also provides a safeguard against unintentionally passing a parameter by reference to another routine.

Here, for example, is the header for the CompareStr function in the SysUtils unit:
function CompareStr(const S1, S2: string): Integer;

Because S1 and S2 are not modified in the body of CompareStr, they can be declared as constant parameters.
Out parameters

An out parameter, like a variable parameter, is passed by reference. With an out parameter, however, the initial value of the referenced variable is discarded by the routine it is passed to. The out parameter is for output only; that is, it tells the function or procedure where to store output, but doesn't provide any input.

For example, consider the procedure heading
procedure GetInfo(out Info: SomeRecordType);

When you call GetInfo, you must pass it a variable of type SomeRecordType:
var MyRecord: SomeRecordType;
...
GetInfo(MyRecord);

But you're not using MyRecord to pass any data to the GetInfo procedure; MyRecord is just a container where you want GetInfo to store the information it generates. The call to GetInfo immediately frees the memory used by MyRecord, before program control passes to the procedure.

Out parameters are frequently used with distributed-object models like COM and CORBA. In addition, you should use out parameters when you pass an uninitialized variable to a function or procedure.
Untyped parameters

You can omit type specifications when declaring var, const, and out parameters. (Value parameters must be typed.) For example,
procedure TakeAnything(const C);

declares a procedure called TakeAnything that accepts a parameter of any type. When you call such a routine, you cannot pass it a numeral or untyped numeric constant.

Within a procedure or function body, untyped parameters are incompatible with every type. To operate on an untyped parameter, you must cast it. In general, the compiler cannot verify that operations on untyped parameters are valid.

The following example uses untyped parameters in a function called Equal that compares a specified number of bytes of any two variables.
function Equal(var Source, Dest; Size: Integer): Boolean;
type
TBytes = array[0..MaxInt - 1] of Byte;
var
N: Integer;
begin
N := 0;
while (N < Size) and (TBytes(Dest)[N] = TBytes(Source)[N]) do
Inc(N);
Equal := N = Size;
end;

Given the declarations
type
TVector = array[1..10] of Integer;
TPoint = record
X, Y: Integer;
end;
var
Vec1, Vec2: TVector;
N: Integer;
P: TPoint;

you could make the following calls to Equal:
Equal(Vec1, Vec2, SizeOf(TVector)) // compare Vec1 to Vec2
Equal(Vec1, Vec2, SizeOf(Integer) * N) // compare first N elements of Vec1 and Vec2
Equal(Vec1[1], Vec1[6], SizeOf(Integer) * 5) // compare first 5 to last 5 elements of Vec1
Equal(Vec1[1], P, 4) // compare Vec1[1] to P.X and Vec1[2] to P.Y
String parameters

When you declare routines that take short-string parameters, you cannot include length specifiers in the parameter declarations. That is, the declaration
procedure Check(S: string[20]); // syntax error

causes a compilation error. But
type TString20 = string[20];
procedure Check(S: TString20);

is valid. The special identifier OpenString can be used to declare routines that take short-string parameters of varying length:
procedure Check(S: OpenString);

When the {$H-} and {$P+} compiler directives are both in effect, the reserved word string is equivalent to OpenString in parameter declarations.

Short strings, OpenString, $H, and $P are supported for backward compatibility only. In new code, you can avoid these considerations by using long strings.
Array parameters

When you declare routines that take array parameters, you cannot include index type specifiers in the parameter declarations. That is, the declaration
procedure Sort(A: array[1..10] of Integer); // syntax error

causes a compilation error. But
type TDigits = array[1..10] of Integer;
procedure Sort(A: TDigits);

is valid. For most purposes, however, open array parameters are a better solution.
Open array parameters

Open array parameters allow arrays of different sizes to be passed to the same procedure or function. To define a routine with an open array parameter, use the syntax array of type (rather than array[X..Y] of type) in the parameter declaration.

For example,
function Find(A: array of Char): Integer;

declares a function called Find that takes a character array of any size and returns an integer.

Note: The syntax of open array parameters resembles that of dynamic array types, but they do not mean the same thing. The example above creates a function that takes any array of Char elements, including (but not limited to) dynamic arrays. To declare parameters that must be dynamic arrays, you need to specify a type identifier:
type TDynamicCharArray = array of Char;
function Find(A: TDynamicCharArray): Integer;

For information about dynamic arrays, see "Dynamic arrays".

Within the body of a routine, open array parameters are governed by the following rules.

They are always zero-based. The first element is 0, the second element is 1, and so forth. The standard Low and High functions return 0 and Length - 1, respectively. The SizeOf function returns the size of the actual array passed to the routine.
They can be accessed by element only. Assignments to an entire open array parameter are not allowed.
They can be passed to other procedures and functions only as open array parameters or untyped var parameters. They cannot be passed to SetLength.
Instead of an array, you can pass a variable of the open array parameter's base type. It will be treated as an array of length 1.


When you pass an array as an open array value parameter, the compiler creates a local copy of the array within the routine's stack frame. Be careful not to overflow the stack by passing large arrays.

The following examples use open array parameters to define a Clear procedure that assigns zero to each element in an array of reals and a Sum function that computes the sum of the elements in an array of reals.
procedure Clear(var A: array of Real);
var
I: Integer;
begin
for I := 0 to High(A) do A[I] := 0;
end;

function Sum(const A: array of Real): Real;
var
I: Integer;
S: Real;
begin
S := 0;
for I := 0 to High(A) do S := S + A[I];
Sum := S;
end;

When you call routines that use open array parameters, you can pass open array constructors to them. See "Open array constructors".
Variant open array parameters

Variant open array parameters allow you to pass an array of differently-typed expressions to a single procedure or function. To define a routine with a variant open array parameter, specify array of const as the parameter's type. Thus
procedure DoSomething(A: array of const);

declares a procedure called DoSomething that can operate on heterogeneous arrays.

The array of const construction is equivalent to array of TVarRec. TVarRec, declared in the System unit, represents a record with a variant part that can hold values of integer, Boolean, character, real, string, pointer, class, class reference, interface, and variant types. TVarRec's VType field indicates the type of each element in the array. Some types are passed as pointers rather than values; in particular, long strings are passed as Pointer and must be typecast to string. See the online Help on TVarRec for details.

The following example uses a variant open array parameter in a function that creates a string representation of each element passed to it and concatenates the results into a single string. The string-handling routines called in this function are defined in SysUtils.
function MakeStr(const Args: array of const): string;
const
BoolChars: array[Boolean] of Char = ('F', 'T');
var
I: Integer;
begin
Result := '';
for I := 0 to High(Args) do
with Args[I] do
case VType of
vtInteger: Result := Result + IntToStr(VInteger);
vtBoolean: Result := Result + BoolChars[VBoolean];
vtChar: Result := Result + VChar;
vtExtended: Result := Result + FloatToStr(VExtended^);
vtString: Result := Result + VString^;
vtPChar: Result := Result + VPChar;
vtObject: Result := Result + VObject.ClassName;
vtClass: Result := Result + VClass.ClassName;
vtAnsiString: Result := Result + string(VAnsiString);
vtCurrency: Result := Result + CurrToStr(VCurrency^);
vtVariant: Result := Result + string(VVariant^);
vtInt64: Result := Result + IntToStr(VInt64^);
end;
end;

We can call this function using an open array constructor (see "Open array constructors"). For example,
MakeStr(['test', 100, ' ', True, 3.14159, TForm])

returns the string "test100 T3.14159TForm".
Default parameters

You can specify default parameter values in a procedure or function heading. Default values are allowed only for typed const and value parameters. To provide a default value, end the parameter declaration with the = symbol followed by a constant expression that is assignment-compatible with the parameter's type.

For example, given the declaration
procedure FillArray(A: array of Integer; Value: Integer = 0);

the following procedure calls are equivalent.
FillArray(MyArray);
FillArray(MyArray, 0);

A multiple-parameter declaration cannot specify a default value. Thus, while
function MyFunction(X: Real = 3.5; Y: Real = 3.5): Real;

is legal,
function MyFunction(X, Y: Real = 3.5): Real; // syntax error

is not.

Parameters with default values must occur at the end of the parameter list. That is, all parameters following the first declared default value must also have default values. So the following declaration is illegal.
procedure MyProcedure(I: Integer = 1; S: string); // syntax error

Default values specified in a procedural type override those specified in an actual routine. Thus, given the declarations
type TResizer = function(X: Real; Y: Real = 1.0): Real;
function Resizer(X: Real; Y: Real = 2.0): Real;
var
F: TResizer;
N: Real;

the statements
F := Resizer;
F(N);

result in the values (N, 1.0) being passed to Resizer.

Default parameters are limited to values that can be specified by a constant expression. (See "Constant expressions".) Hence parameters of a dynamic-array, procedural, class, class-reference, or interface type can have no value other than nil as their default. Parameters of a record, variant, file, static-array, or object type cannot have default values at all.

For information about calling routines with default parameter values, see "Calling procedures and functions".
Default parameters and overloaded routines

If you use default parameter values in an overloaded routine, avoid ambiguous parameter signatures. Consider, for example, the following.
procedure Confused(I: Integer); overload;
...
procedure Confused(I: Integer; J: Integer = 0); overload;
...
Confused(X); // Which procedure is called?

In fact, neither procedure is called. This code generates a compilation error.
Default parameters in forward and interface declarations

If a routine has a forward declaration or appears in the interface section of a unit, default parameter values--if there are any--must be specified in the forward or interface declaration. In this case, the default values can be omitted from the defining (implementation) declaration; but if the defining declaration includes default values, they must match those in the forward or interface declaration exactly.
Calling procedures and functions

When you call a procedure or function, program control passes from the point where the call is made to the body of the routine. You can make the call using the routine's declared name (with or without qualifiers) or using a procedural variable that points to the routine. In either case, if the routine is declared with parameters, your call to it must pass parameters that correspond in order and type to the routine's parameter list. The parameters you pass to a routine are called actual parameters, while the parameters in the routine's declaration are called formal parameters.

When calling a routine, remember that

expressions used to pass typed const and value parameters must be assignment-compatible with the corresponding formal parameters.
expressions used to pass var and out parameters must be identically typed with the corresponding formal parameters, unless the formal parameters are untyped.
only assignable expressions can be used to pass var and out parameters.
if a routine's formal parameters are untyped, numerals and true constants with numeric values cannot be used as actual parameters.


When you call a routine that uses default parameter values, all actual parameters following the first accepted default must also use the default values; calls of the form SomeFunction(,,X) are not legal.

You can omit parentheses when passing all and only the default parameters to a routine. For example, given the procedure
procedure DoSomething(X: Real = 1.0; I: Integer = 0; S: string = '');

the following calls are equivalent.
DoSomething();
DoSomething;
Open array constructors

Open array constructors allow you to construct arrays directly within function and procedure calls. They can be passed only as open array parameters or variant open array parameters.

An open array constructor, like a set constructor, is a sequence of expressions separated by commas and enclosed in brackets. For example, given the declarations
var I, J: Integer;
procedure Add(A: array of Integer);

you could call the Add procedure with the statement
Add([5, 7, I, I + J]);

This is equivalent to
var Temp: array[0..3] of Integer;
...
Temp[0] := 5;
Temp[1] := 7;
Temp[2] := I;
Temp[3] := I + J;
Add(Temp);

Open array constructors can be passed only as value or const parameters. The expressions in a constructor must be assignment-compatible with the base type of the array parameter. In the case of a variant open array parameter, the expressions can be of different types.

4 Responses so far.

Post a Comment

Thank you for your comment.

Any request and idea are welcome.

CLICK TO REGISTER