Under the hood of an anonymous method

I woke up this morning and checked DelphiFeeds, and found a very interesting post by Jolyon Smith about the use of the absolute keyword.  That reminded me that I had to go and write up this article.  Why?  Because it’s the only way I know of to get inside an anonymous method’s functor object and do some looking around.

It’s been explained several times by several different people, including me in my last article about anonymous methods, that anonymous methods are implemented through interfaces.  And all it takes is a trivial little console application to writeln the sizeof a reference to variable and come up with 4, the size of a pointer.  Interestingly enough, though, the compiler won’t allow you to typecast a reference to to an IInterface, a Pointer, an Integer or anything else.  It’s an anonymous method reference and it won’t be anything else no matter what you do.

…unless, of course, you have another variable occupying the same four bytes of memory.  Something like this:

[code lang="delphi"]
procedure TClassViewer.FormShow(Sender: TObject);
var
   proc: TProc;
   func: TFunc;
   intf: IInterface absolute proc;
begin
   ReportMemoryLeaksOnShutdown := true;
   proc := procedure()
   begin
      assert(sender is TObject);
   end;
   func := function(): string
   begin
      result := sender.ClassName;
   end;
   loadClass(intf as TObject);
end;
[/code]

I set this up to load itself into my class RTTI inspector tool, and used Delphi 2010’s trick of casting an interface to an object, and it worked! And here’s what the object looks like:

anon_rtti_1

The name of the functor object’s class is the full name of the enclosing method, plus $ActRec tacked onto it. Its parent class is TInterfacedObject.

anon_rtti_2

It implements two interfaces, one for each anonymous method. (There’s a third, IInterface, at the TInterfacedObject level, of course.)

anon_rtti_3

Interestingly enough, even though the compiler goes to great pains to make sure this is only treated as an anonymous method and never as an actual object, Delphi 2010 still generates extended RTTI for the variables that the closure captures.

There’s not too much to see in the other tabs, but if you want to explore further with some more complex functor objects, feel free to download the RTTI inspector and take a look around.

5 Comments

  1. Jolyon Smith says:

    Fascinating stuff!

  2. Polprav says:

    Hello from Russia!
    Can I quote a post in your blog with the link to you?

  3. Mason Wheeler says:

    Sure, go ahead.