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.

This entry was posted in Source Code. Bookmark the permalink.

6 Responses to How to Reference a Procedure

  1. David Heffernan says:

    That’s not an alias. It’s a procedural variable. Different from a procedure.

    With a type alias, the type and its alias are indistinguishable. That’s not the case with a procedure a procedural variable.

  2. Jeff Martin says:

    Jim, thank you very much for this simple tutorial! I’ve needed to do this kind of thing (with members of an object) a few times and I was never able to figure out how to do it, or if it was even possible. Now I know thanks to you!

  3. Jeff Martin says:

    @David Heffernan – Right you are, but is there really a way you know of to actually alias a procedure in the true sense of the term?

  4. David Heffernan says:

    No I don’t think there is. I do think that terminology and detail are important. Using terminology in a sloppy and imprecise manner is not constructive, in my view.

  5. alexdmatveev says:

    I am on David’s side. To avoid mix in your head when you start to work with anonymous methods it is very useful to have in head right words and termins. When you have wrong ones it is very difficult to read 3rd party documentations and so on.

    Also I would advice to read about generics aspect of procedural type. It is really cool and easy to use (TFunc, TPredicate and so on).

    Procedure alias is not very often to meet in theoretical documentation about amonymous methods and lamdba functions. It is really better to refer it as procedural or functional (Scala is example here) type.

  6. Jim McKeeth says:

    Added clarification.

Leave a Reply