When a procedural variable is on the left side of an assignment statement, the compiler expects a procedural value on the right. The assignment makes the variable on the left a pointer to the function or procedure indicated on the right. In other contexts, however, using a procedural variable results in a call to the referenced procedure or function. You can even use a procedural variable to pass parameters:
Código Delphi
[-]
var
F: function(X: Integer): Integer;
I: Integer;
function SomeFunction(X: Integer): Integer;
...
F := SomeFunction; I := F(4);
In assignment statements, the type of the variable on the left determines the interpretation of procedure or method pointers on the right. For example,
Código Delphi
[-]
var
F, G: function: Integer;
I: Integer;
function SomeFunction: Integer;
...
F := SomeFunction; G := F; I := G;
The first statement assigns a procedural value to F. The second statement copies that value to another variable. The third statement makes a call to the referenced function and assigns the result to I. Because I is an integer variable, not a procedural one, the last assignment actually calls the function (which returns an integer).
In some situations it is less clear how a procedural variable should be interpreted. Consider the statement
if F = MyFunction then ...;
In this case, the occurrence of F results in a function call; the compiler calls the function pointed to by F, then calls the function MyFunction, then compares the results. The rule is that whenever a procedural variable occurs within an expression, it represents a call to the referenced procedure or function. In a case where F references a procedure (which doesn’t return a value), or where F references a function that requires parameters, the statement above causes a compilation error. To compare the procedural value of F with MyFunction, use
if @F = @MyFunction then ...;
@F converts F into an untyped pointer variable that contains an address, and @MyFunction returns the address of MyFunction.
To get the memory address of a procedural variable (rather than the address stored in it), use @@. For example, @@F returns the address of F.
The @ operator can also be used to assign an untyped pointer value to a procedural variable. For example,
var StrComp: function(Str1, Str2: PChar): Integer;
...
@StrComp := GetProcAddress(KernelHandle, 'lstrcmpi');
calls the GetProcAddress function and points StrComp to the result.
Any procedural variable can hold the value nil, which means that it points to nothing. But attempting to call a nil-valued procedural variable is an error. To test whether a procedural variable is assigned, use the standard function Assigned:
if Assigned(OnClick) then OnClick(X);