Variant Invoke and RTTI

I was “spring cleaning” my temporary project directory on my hard drive today and I found a half-finished implementation of a dynamic dispatch for objects based on new RTTI (Delphi 2010+). I spent some time and fixed the last issues I had and now I think it’s ready to be published.

All the code is enclosed in a single unit (there’s not that much code actually) that exposes one function called “AsDynamic“. This method expects a normal non-nil object, a lifetime management flag and returns a custom Variant value.  The Variant can be used later on to dynamically invoke any method/property on that object.

The following example shows a wrapped TStringList object:

var
  LVarList: Variant;
begin
  { Create a new String List and wrap it into a Variant. By default the Variant will also take care about freeing the object. }
  LVarList := AsDynamic(TStringList.Create);

  { Add two strings to the string list. Note that Add() is called dynamically here. }
  LVarList.Add('Hello World!');
  LVarList.Add('Cool string');

  { Make the list sorted (also dynamically) }
  LVarList.Sorted := True;

  { ... And finally write the contents of the list }
  WriteLn(LVarList.Text);
end.

I don’t see any practical uses this code but it’s good for learning purposes. It can also be a simplified way of treating the cases when one has to execute the same code on classes that do not share a common ancestor or cannot implement an interface.

Just a quick note on what you can see inside the unit:

  • Defining a custom Variant type by extending TInvokeableVariantType and providing the proper support code.
  • An intermediate object and an interface that contain the wrapped object and RTTI structures needed for dynamic invoke. The custom Variant type carries over this object (actually an interface reference).
  • TValue to Variant and Variant to TValue conversion. Since the dynamic dispatch uses variants for arguments a conversion is required in both directions. This is simple in most cases but rather complicated for var and out parameters.

Note that dynamic dispatch as implemented by Delphi has quite a few restriction in what types are allowed and how exactly those values are passed to the invoked methods. For example literals are passed by value and variables are passed by reference (not always!). This is due to the nature of “not knowing” what exactly the method behind expects. As an example, you cannot pass a String by reference while a WideString variable is always passed by reference.

The code can be found here: [download#43]