RTTI and enumerators

I’ve been doing a lot of work with the new RTTI system lately, figuring out how to take an arbitrary object and upload its data to a TClientDataset, or serialize it to a file.  I’ve got it working, and most of it was pretty straightforward once I managed to wrap my brain around the RTTI system.

Getting inside a generic list, though, was a bit of a hack.  Since Delphi 2010 doesn’t support covariance and contravariance on generic classes, you can’t take a routine that accepts “a TList<T>” and enumerate over all its contents, even if you constrain T to only descendants of a specific base class.  What I ended up doing is kinda ugly:

[code lang="delphi"]
procedure TDatafile.uploadList(db: TDataset; const value: TValue; fieldname: string);

   function isUploadable(method: TRttiMethod): boolean;
   var
      param: TArray<TRttiParameter>;
      enumerator: TRttiType;
      prop: TRttiProperty;
      retval: TRttiType;
   begin
      result := false;
      param := method.GetParameters;
      if not (length(method.GetParameters) = 0) then
         Exit;
      enumerator := method.ReturnType;
      if not assigned(enumerator) then
         Exit;
      prop := enumerator.GetProperty('current');
      if not assigned(prop) then
         Exit;
      retval := prop.PropertyType;
      result := (retval is TRttiInstanceType);
   end;

var
   iType: TRttiInstanceType;
   enumMethod: TRttiMethod;
begin
   assert(value.Kind = tkClass);
   iType := FContext.GetType(value.TypeInfo) as TRttiInstanceType;
   enumMethod := iType.GetMethod('GetEnumerator');
   assert(assigned(enumMethod) and (isUploadable(enumMethod)));
   uploadEnumerable(db, value, enumMethod, fieldname);
end;

procedure TDatafile.uploadEnumerable(db: TDataset; const value: TValue;
  uploadMethod: TRttiMethod; fieldName: string);
var
   enumerator: TObject;
   enumType: TRttiType;
   current: TRttiProperty;
   moveNext: TRttiMethod;
   datafile: TDatafile;
begin
   enumerator := uploadMethod.Invoke(value, []).AsObject;
   enumType := FContext.GetType(enumerator.ClassInfo);
   current := enumType.GetProperty('Current');
   moveNext := enumType.GetMethod('MoveNext');

   while moveNext.Invoke(enumerator, []).AsBoolean do
   begin
      datafile := current.GetValue(enumerator).AsType<TDatafile>;
      db.Append;
      datafile.upload(db);
   end;
   if db.state in dsEditModes then
      db.Post;
   enumerator.Free;
end;
[/code]

There’s some unrelated code mixed in which is specific to the way I’m uploading the objects to the datasets, but this is mainly about enumerating a generic list of an unknown type.  Basically, we’re doing manually what the language-level enumerator support does automatically, extracting and validating the enumerator and running the enumeration by hand.  Scary, no?  There’s gotta be a better way.

What I’d really like to see is something like this.  TRttiStructuredType (the base class for TRttiRecordType, TRttiInstanceType and TRttiInterfaceType) should get two methods:

function TRttiStructuredType.IsEnumerable: boolean;

function TRttiStructuredType.GetEnumerator: TRttiEnumerator; //returns nil if IsEnumerable is false

The TRttiEnumerator would basically do what my code above does: crack open the underlying type’s enumerator and run it, returning an enumerated sequence of TRttiObject objects.  But in order for that to work well, (without the sort of ugly hacks you see above,) it needs compiler-level support.  Maybe we can hope to see it in D2011?

StringList Comparison

A few weeks ago I wrote about using the List Comparison algorithm to optimize a slow nested loop.  This evening I saw someone on the Delphi forums asking about a way to compare two TStringLists, so I wrote up a quick version of the List Comparison algorithm specifically for TStringLists.  I used the basic algorithm as a higher-order function that you can pass method pointers to to configure its behavior, and added a few built-in comparison functions that perform common tasks.  You can find it in the Downloads page.  I’m working on a List Comparison library that uses generics and anonymous methods to compare TList<T> descendants, but it’s not done yet.  I’ll post it here when it’s ready.

As-sertion casting

So you’ve got some code that you know has to be in a certain state. It can’t be proven at compile-time, but you know that it has to be like this, and if it wasn’t, it could cause some serious problems. But you’re a good, careful coder, and you don’t want to just assume that the state of the program will be a certain way just because you think it should. You know better than that, so you add a bit of special code to verify your assumptions. And if it turns out you were wrong, it’ll raise an exception that you almost certainly have nothing in place to catch at any level before the global exception handler for your app.

Sound familiar? It should. You probably do it all the time. It’s an as-cast.
Continue reading ‘As-sertion casting’ »

How to leak a class you never defined

Quick, what’s wrong with this code?

[code lang="delphi"]
procedure ContrivedExample;
var
   factorial: TFunc;
begin
   factorial :=
      function(input: Integer): integer
      begin
         if (input = 0) or (input = 1) then
            result := input
         else result := input * (factorial(input - 1));
      end;

   writeln(factorial(5));
end;
[/code]

Continue reading ‘How to leak a class you never defined’ »

Real-world optimization

Last week at work, I was asked to look at one of our verification modules that was taking about three times longer to run than it had in an earlier version.  This module takes a set of result files, compares them against another file showing expected results, and reports any discrepancies that are outside the defined margin of error.  It’s some pretty heavy work involving hundreds of thousands of data points, and the old version already took more than ten minutes.  Increasing the running time by a factor of three just wasn’t acceptable.  So I started to look at what was going on.

Continue reading ‘Real-world optimization’ »

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.

Continue reading ‘Under the hood of an anonymous method’ »

Asking the impossible

On TVTropes, one of my favorite websites, there’s a phrase that’s only invoked when an author writes about something real, but uses it in a way that’s impossible and completely contrary to its nature: “X does not work that way.”  For example, if a sci-fi show features space fighters dogfighting and making turns that would only be possible with atmospheric friction against the hull, or gradually drifting to a stop if the engines stop thrusting, that might get listed under “Space does not work that way.”

What does this have to do with Delphi programming?  Bear with me.  Continue reading ‘Asking the impossible’ »

What’s in a name-less method?

When I first saw the announcements for the new Delphi 2009 features, a little more than a year ago, my reactions went something like this:

Unicode: Hmm… looks interesting.
Generics: YES! FINALLY!
Anonymous methods: …huh?

I think that’s pretty much how everyone reacted to anonymous methods at first.  Continue reading ‘What’s in a name-less method?’ »

Dynamic class creation

NOTE: The download link in the original version of this post got mangled by WordPress. It’s been corrected now.

A couple weeks ago, I gave a presentation at the CodeRage 4 online conference about dynamic class creation at runtime in Delphi.  The replays were just posted yesterday at Embarcadero’s CodeRage siteContinue reading ‘Dynamic class creation’ »