Calling Procedures and Functions (Delphi)

From RAD Studio
Jump to: navigation, search

Go Up to Procedures and Functions Index

This topic covers the following items:

  • Program control and routine parameters
  • Open array constructors
  • The inline directive

Program Control and Parameters

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 declared name of the routine (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 parameter list of the routine. The parameters you pass to a routine are called actual parameters, while the parameters in the declaration of the routine 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 the formal parameters of a routine 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.

Using the inline Directive

The Delphi compiler allows functions and procedures to be tagged with the inline directive to improve performance. If the function or procedure meets certain criteria, the compiler will insert code directly, rather than generating a call. Inlining is a performance optimization that can result in faster code, but at the expense of space. Inlining always causes the compiler to produce a larger binary file. The inline directive is used in function and procedure declarations and definitions, like other directives.

procedure MyProc(x:Integer); inline;
begin
    // …
end;

function MyFunc(y:Char) : String; inline;
begin
  // …
end;

The inline directive is a suggestion to the compiler. There is no guarantee the compiler will inline a particular routine, as there are a number of circumstances where inlining cannot be done. The following list shows the conditions under which inlining does or does not occur:

  • Inlining will not occur on any form of late-bound method. This includes virtual, dynamic, and message methods.
  • Routines containing assembly code will not be inlined.
  • Constructors and destructors will not be inlined.
  • The main program block, unit initialization, and unit finalization blocks cannot be inlined.
  • Routines that are not defined before use cannot be inlined.
  • Routines that take open array parameters cannot be inlined.
  • Code can be inlined within packages, however, inlining never occurs across package boundaries.
  • No inlining is done between units that are circularly dependent. This includes indirect circular dependencies, for example, unit A uses unit B, and unit B uses unit C which in turn uses unit A. In this example, when compiling unit A, no code from unit B or unit C will be inlined in unit A.
  • The compiler can inline code when a unit is in a circular dependency, as long as the code to be inlined comes from a unit outside the circular relationship. In the above example, if unit A also used unit D, code from unit D could be inlined in A, since it is not involved in the circular dependency.
  • If a routine is defined in the interface section and it accesses symbols defined in the implementation section, that routine cannot be inlined.
  • If a routine marked with inline uses external symbols from other units, all of those units must be listed in the uses statement, otherwise the routine cannot be inlined.
  • Within a unit, the body for an inline function should be defined before calls to the function are made. Otherwise, the body of the function, which is not known to the compiler when it reaches the call site, cannot be expanded inline.

If you modify the implementation of an inlined routine, you will cause all units that use that function to be recompiled. This is different from traditional rebuild rules, where rebuilds were triggered only by changes in the interface section of a unit.

The {$INLINE} compiler directive gives you finer control over inlining. The {$INLINE} directive can be used at the site of the inlined definition of the routine, as well as at the call site. Below are the possible values and their meaning:

Value Meaning at definition Meaning at call site

{$INLINE ON} (default)

The routine is compiled as inlineable if it is tagged with the inline directive.

The routine will be expanded inline if possible.

{$INLINE AUTO}

Behaves like {$INLINE ON}, with the addition that routines not marked with inline will be inlined if their code size is less than or equal to 32 bytes.

{$INLINE AUTO} has no effect on whether a routine will be inlined when it is used at the call site of the routine.

{$INLINE OFF}

The routine will not be marked as inlineable, even if it is tagged with inline.

The routine will not be expanded inline.

See Also