3.6 Procedural types

Free Pascal has support for procedural types, although it diers a little from the Turbo Pascal implementation of them. The type declaration remains the same, as can be seen in the following syntax diagram:

_________________________________________________________________________________________________________ Procedural types
-- --procedural type-|-function header----|------------|-----------------
                   -procedure header- -of- object-- -; -call modi ers--

-- --function header- function -formal parameter list :-result type----------

-- --procedure header procedure- formal parameter list--------------------

-- --call modi ers---register ------------------------------------------
                 --cdecl--|
                 --pascal--|
                 |-stdcall--|
                 |safecall-|
                 --inline --
___________________________________________________________________

For a description of formal parameter lists, see chapter 10, page 348. The two following examples are valid type declarations:

Type TOneArg = Procedure (Var X : integer);  
     TNoArg = Function : Real;  
var proc : TOneArg;  
    func : TNoArg;

One can assign the following values to a procedural type variable:

  1. Nil, for both normal procedure pointers and method pointers.
  2. A variable reference of a procedural type, i.e. another variable of the same type.
  3. A global procedure or function address, with matching function or procedure header and calling convention.
  4. A method address.

Given these declarations, the following assignments are valid:

Procedure printit (Var X : Integer);  
begin  
  WriteLn (x);  
end;  
...  
Proc := @printit;  
Func := @Pi;

From this example, the dierence with Turbo Pascal is clear: In Turbo Pascal it isn't necessary to use the address operator (@) when assigning a procedural type variable, whereas in Free Pascal it is required (unless the -So switch is used, in which case the address operator can be dropped.)

Remark: The modiers concerning the calling conventions must be the same as the declaration; i.e. the following code would give an error:

Type TOneArgCcall = Procedure (Var X : integer);cdecl;  
var proc : TOneArgCcall;  
Procedure printit (Var X : Integer);  
begin  
  WriteLn (x);  
end;  
begin  
Proc := @printit;  
end.

Because the TOneArgCcall type is a procedure that uses the cdecl calling convention.