Categories
Source Code

How to Reference a Procedure

It was pointed out in the comments and on G+ that this covers type aliases, but not procedure aliases. Instead it shows how to have a variable that references a procedure and then allows you to call it by this new variable. While I used alias as meaning “reference by a different name” it does in fact have a specific definition in this context. Sorry if there was any confusion or undue frustration at imprecise terminology.

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 reference variable of the right type, and assign it to the procedure we want to alias reference. If you call an alias reference 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 reference 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.

Categories
Audio podCast podcast

Podcast Episode 60 – Victory Fernandes

In this episode I talk with Embarcadero MVP Victory Fernandes from Salvador, Brazil. While Victory is from Brazil, he also speaks fluent English.

Victory Fernandes

Victory talks about:

Most all of Victory’s projects are powered by Delphi and InterBase with emphasis on embedded and real-time application development.