Archive for the ‘Delphi’ Category.

How to break the D2010 compiler

I really loved when Delphi 2009 came out, how it fixed so many ugly problems in the Delphi IDE.  The stability issues and memory leaks that plagued D2006 and D2007 were greatly reduced.  And it just got better in D2010.

The tradeoff, though, seems to have been compiler stability.  Trying to do anything with Generics in D2009 before Update 3 came out was a nightmare, and even after, (and even in D2010,) there were still plenty of dark corners where you can end up with an Internal Compiler Error or linker error on something that, syntactically speaking at least, is perfectly cromulent Object Pascal.

Continue reading ‘How to break the D2010 compiler’ »

Random musing: TStringList

A while back, Jim McKeeth told me (jokingly, of course) that with a TStringList and a TDataset, you can solve any programming problem.  He also likes to compare TStringList to a Swiss Army Knife, because it can do so many things.  And it sort of made me wonder.  Continue reading ‘Random musing: TStringList’ »

Learning Delphi: A true story

It’s pretty common where I work to go out to lunch together with other coworkers. We’re located downtown, right across the street from a major shopping mall and with plenty of restaurants within walking distance. A few months ago I was out with a few of the other coders, and one of the guys, David, told the story of how he got into programming. It made quite an impression on me. You’ll see why. Unfortunately he’s no longer with the company, so I can’t get the exact story from him to retell here, but I’ll give the idea of it here.

Disclaimer: Even when I give the story from his perspective, they aren’t exact quotes by any means. My memory’s real good, but not that good! But this is the basic idea of what he said, with no ficionalizing.

He wasn’t originally a computer programmer. Hadn’t even really studied it in college. David’s degree was in accounting, and he was working as an accountant with an insurance company back in the 90s. He explained, “They had a tuition reimbursement program set up with the local college. You could take classes there, and as long as you got a B or better at the end of the semester, they’d pay you back for the courses. The tuition was several hundred dollars per course, so you had a pretty strong incentive to do well in them!

“Anyway, I was working with this insurance company, and my job was to take care of custom policies. They had this thing where they’d write out custom policies for all the small businesses in the area, which were all more or less from the same template but with a bunch of cudtomized details tailored to each one. And every month I’d get this big stack of a few hundred sheets of printer paper and have to crunch all the numbers. It was annoying, really tedious work.” We commiserated with him about how much that must have sucked, as we sat there waiting for our orders to arrive.

“After a while I got them to give me direct access to the database to read these values from, instead of giving me a printout from it, and that helped a bit, but there was still a lot of stuff I had to do by hand. I got to thinking that this was the sort of thing that could be simplified by writing a computer program, if only I knew how to. Well, they had a course at the college on database programming, and I signed up for it.”

He looked at us a bit wryly and said, “To this day I don’t know how I actually got into the class. I wasn’t paying enough attention when I registered for it. Turns out it was a graduate-level Computer Science course! I didn’t have any CS background, and after the first day in the class I was completely lost. The entire grade for the semester was based on a project. You needed to create a database program to solve a real-world problem. And it had to have a graphical user interface, it had to have reporting…” he listed off several requirements, and this was about where I saw where the story was headed. It was almost like he was reading off a lit of Delphi’s historical strong points.

“I was completely lost. I didn’t even know where to start! But I’d already paid the tuition and I couldn’t get it back without a B or better in the class. So I went to talk to a friend of mine who was a professor in the CS department. I explained the problem to him, and he listened, and when I was done he thought about it for a moment. ‘Well,’ he said, ‘you could try Visual Basic, but there’s this new thing that just came out that might work better for you. It’s called Delphi.’ He was able to get me set up with a copy, and I installed it on my computer at work.

“For the next few months, that’s pretty much what my life was about. I’d work on my job during the day, then stay after in the evening to figure out how to use Delphi and how to make it talk to a database. Needless to say, I didn’t get very much sleep! But when the end of the semester rolled around, I had a working program. And I ended up getting an A on the class.”

Ladies and gentlemen, that right there is a testament to the power of the Delphi language! From a cold start, no programming background at all, to writing an app good enough to ace a graduate-level CS course in a matter of months. Granted, David’s a very intelligent guy, and that certainly played a part in being able to pick it up so quickly, but even so, a lot of it’s the Delphi language itself. (You’d never see results like that in the C family!)

Delphi is an evolution of Pascal, which was originally created by Niklaus Wirth as a teaching language. Being easy to learn was an explicit design goal. That originally came with a few tradeoffs and drawbacks, but the Borland team managed to extend the language into a powerful general-purpose programming system while still holding to the Pascal philosophy of making the language’s syntax and semantics as intuitive and easy to understand as they could. That’s what made it possible for David to pick up so quickly, and that’s why even experienced programmers who have been coding for years love Delphi: the language just makes sense. It may not have <insert trendy feature from some other language here>, but language design makes the code, even code the dreaded “other people’s” variety, easier to read and comprehend, and that counts for a lot in modern team-based software development.

In Object Pascal, things make sense, and they tend to work right even if you don’t quite understand them. IMO this is the main reason why so many people who know Delphi actually find it enjoyable to work with, as opposed to just something they write code in because they need to get something written, and why they sometimes even go so far as to call it “the best programming language.”

Abusing extended RTTI for fun and profit

I’ll admit, I don’t like the default settings for Delphi 2010’s extended RTTI.  Making almost everything included by default ends up compiling a ton of junk into the EXE, most of which will never get used.  But every once in a while, you can find some sort of use for it.

Continue reading ‘Abusing extended RTTI for fun and profit’ »

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’ »