3.6 Procedural types

Free Pascal has support for procedural types, although it differs 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 modifiers-

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

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

--           -----      -----------------------------------------
   call modifiers ---register----|
               ---pcadsecclal----|
               ---stdcall----|
               ---safecall----|
               |saveregisters--|
               --popstack ---
___________________________________________________________________

For a description of formal parameter lists, see chapter 8, page 288. 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 difference 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 modifiers 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.