How to Alias a Procedure

  

I just answered a question about how to alias a procedure. I thought it was interesting enough to share here.
It is easy enough to alias a type . . .
type
my_integer = integer;

then we can just use my_interger in place of integer as a type. But what about a procedure (or function for that matter)?
There are two different ways, depending on if the procedure is a member of a class. For straight up procedural procedures and functions it looks a little something like this:
procedure HelloWorld; // declare our procedure
begin
ShowMessage(‘Hi’);
end;

var
my_proc: Procedure; // declare our alias

begin
my_proc := HelloWorld; // assign the alias

// …

if assigned(my_proc) then // verify the reference
my_proc; // call the alias
end;
This is pretty straight forward. We just create an alias variable of the right type, and assign it to the procedure we want to alias. If you call an alias variable that is unassigned you will get a null reference access violation.
You can also streamline it a little like this
var // or as const
my_proc: procedure = HelloWorld;
Then you know it is assigned. I guess this would be useful if you want to alias a procedure declared in a different unit.
This works the same for functions or procedures with parameters.
procedure Hello(name: String);
begin
ShowMessage(‘Hello ‘ + name);
end;

function Nine: integer;
begin
Result := 9;
end;

var
argumentative: procedure(s: string) = Hello;
number: function: integer = Nine;
Notice that the name of the argument doesn’t have to match, but the number, order and types do. If they don’t then you will get the error
E2009 Incompatible types: ‘Parameter lists differ’
Now what if you are dealing with procedures or functions that are members of an object? If you try to assign them to the above types you will get the error
E2009 Incompatible types: ‘regular procedure and method pointer’
And that is because members of an object are method pointers. Fear not, you can handle them with just a slightly different type declaration:
type
TMethod = procedure of object;
TFunc = function: integer of object;
TNotifyEvent = procedure(Sender: TObject) of object;
In this case they are declared as types with “of object” added to the end. This indicates that they are procedures of an object. AKA members or method pointers.
You can read more about procedural types and method pointers in the DocWiki.
Why would you want to do any of this? First of all, the method pointer is how the VCL & FMX handles dependency injection through event handlers. This is also really useful when combined with anonymous methods and the parallel programming library.

Comments are closed.