Retrofitting a classic
When Delphi 2 was released targeting the 32bit Windows API there were some new-to-Delphi features of the operating system that opened up some new possibilities; Pre-emptive multi-tasking and multi-threading. Coupled with this "new" concept of a "thread," Delphi introduced the new TThread class that was an abstract base class from which one would derived in order to "wrap" an operating system thread. Along with this new functionality, a rather contrived demo was also introduced that showcased this overall notion of "multi-threaded" programming by visually representing the speed differences between three different sorting algorithms, the Bubble-Sort, the Selection-Sort and the Quick-Sort. That demo has remained virtually unchanged ever since. One thing this demo also showed was a way to update the UI by "synchronizing" the sorting thread with the main, or UI thread. This ensured that any UI updates occurred only on the UI thread and only when the UI thread was ready. Even though this is not the best technique in terms of performance, it is safe.
This synchronization was accomplished through the use of the Synchronize method on TThread which took a parameterless method as the parameter which would then block the calling thread, switch to the main, or UI thread, call the method and then return. Since this method took no parameters it was often very tedious to pass information from the running thread over to the UI thread. As the thread demo showed, this involved communicating the parameter data with the foreground by storing this data in fields on the TThread descendant instance. This worked fine even though it was cumbersome.
Fast-forward to now. Delphi 2009 was recently announced and in fact just went "gold" yesterday, Sunday, September 7th, 2008 at around 4pm PDT. One of the more exciting language features to be included in this release aside from generics, is anonymous methods or more accurately, closures. The reason we call them anonymous methods is two-fold. The corresponding concept in .NET is also called an anonymous methods and in C++Builder a method pointer is already declared using the extended __closure keyword syntax. Rather than introduce confusion among both Delphi and C++Builder customers we opted for the "Anonymous Method" moniker. However, for those computer science purists, you can most certainly think of them as true closures, but I digress :-). Because of this new-fangled anonymous method thingy, a new Synchronize overload was added to TThread that now takes a parameterless anonymous method. Here’s the old code in the thread demo that would update the UI:
{ Since DoVisualSwap uses a VCL component (i.e., the TPaintBox) it should never
be called directly by this thread. DoVisualSwap should be called by passing
it to the Synchronize method which causes DoVisualSwap to be executed by the
main VCL thread, avoiding multi-thread conflicts. See VisualSwap for an
example of calling Synchronize. }
procedure TSortThread.DoVisualSwap;
begin
with FBox do
begin
Canvas.Pen.Color := clBtnFace;
PaintLine(Canvas, FI, FA);
PaintLine(Canvas, FJ, FB);
Canvas.Pen.Color := clRed;
PaintLine(Canvas, FI, FB);
PaintLine(Canvas, FJ, FA);
end;
end;
{ VisusalSwap is a wrapper on DoVisualSwap making it easier to use. The
parameters are copied to instance variables so they are accessable
by the main VCL thread when it executes DoVisualSwap }
procedure TSortThread.VisualSwap(A, B, I, J: Integer);
begin
FA := A;
FB := B;
FI := I;
FJ := J;
Synchronize(DoVisualSwap);
end;
Notice that it takes two methods, the one called from within the thread and then the one that is "synchronized" with the UI thread. You need to declared these methods on the class, which can sometimes be tedious. Also, this code requires manual assignment of the instance fields from the parameters. What if you could just pass in the code to synchronize along with the local state? With anonymous methods this is easy. Here’s the above code changed to use an inlined anonymous method:
procedure TSortThread.VisualSwap(A, B, I, J: Integer);
begin
Synchronize(procedure
begin
with FBox do
begin
Canvas.Pen.Color := clBtnFace;
PaintLine(Canvas, I, A);
PaintLine(Canvas, J, B);
Canvas.Pen.Color := clRed;
PaintLine(Canvas, I, B);
PaintLine(Canvas, J, A);
end;
end);
end;
By using an anonymous method, I’ve eliminated the DoVisualSwap method and removed the need for the FA, FB, FI, and FJ instance fields. Once you get used to the new syntax, this code is much easier to understand an use.
Share This | Email this page to a friend
Posted by Allen Bauer on September 8th, 2008 under CodeGear |30 Responses to “Retrofitting a classic”
Leave a Comment
Server Response from: dnrh1.codegear.com

September 8th, 2008 at 2:35 pm
That’s just great!
September 8th, 2008 at 5:34 pm
Awesome… lots of nice new features, now I just hope Delphi 2009 is fast and stable!
September 8th, 2008 at 5:34 pm
I’m not sure I see the point of this (maybe it’s the example used). If I want to do the above several times in different places. The approach used first would seem better. If anonymous methods are only useful as a one shot, then they are not too useful at all. It also precludes the separation of implementation and specification.
September 8th, 2008 at 10:27 pm
The quicksort demo isn’t the only demo that hasn’t changed since Delphi 2.
I’m just sayin… Best foot forward over a decade ago, might just be wearing a mighty scuffed up shoe nowaways, ya know?
Maybe that’s why the demos are now next to impossible to find?
Maybe a nice page in the welcome section that at least had nice HTML markup describing each demo and what it did and then let people load it up easily… Might reduce that new user curve maybe?
Sorry, I know, that really wasn’t what your post was about, and the anonymous sync stuff is a nice touch. Maybe if there was a way to find the demo and a description about in the.. err, sorry folks, a bit of backsliding there.
September 8th, 2008 at 10:43 pm
Oops, I see part of the point. But I’m still not convinced.
September 8th, 2008 at 11:52 pm
Nice example, also good to demo "live", since the actual thrddemo project that ships with Delphi 2009 appears to use the old way (so the project can be used as example to modify in order to use anonymous methods).
September 9th, 2008 at 3:19 am
Nice. Did you also add an overloaded Sort method to TList that accepts an anonymous compare function?
September 9th, 2008 at 3:31 am
Can the anonymous method passed to Synchronize method
access any class variable? most likely it can’t since
the code generated will not push self pointer.
procedure TSortThread.VisualSwap(A, B, I, J: Integer);
begin
Synchronize(procedure
begin
// accessing a class variable…
if (FSomething > 0) then
begin
// do something…
end;
end);
end;
September 9th, 2008 at 6:50 am
Speaking of the demos….
You know, many of us in the Delphi community would be willing to help make the "Delphi experience" better for new users, to grow the user base.
Would it make sense for CodeGear to run a contest for best replacement for the existing demo programs (and maybe some new areas too)? I’ll bet most of us would contribute something for a T-Shirt or hat (to replace our obsolete Borland ones!).
If you want to be cheap, contest winners could get a free "Software Assurance" subscription for a year. That generally ends up not costing you anything anyway, since the releases have been just over a year apart. (Note the lack of a smiley there.)
Or if you want to be nice, maybe a free license for a pro version of Delphi or C++ builder.
September 9th, 2008 at 8:08 am
ahmoy,
If you mean instance variables, yes you can access them. In fact the demo I presented does. The "FBox" variable in the "with" statement is an instance variable. The same for class variables, which are really global variables scoped to the class type.
Allen.
September 9th, 2008 at 8:10 am
Victor,
Not to the existing TList, no. We have, however, introduced a complement of generic classes that do allow you to pass in an anonymous method for the compare function. In Generics.Collections.pas there is a TList<T> which allows you to create a TList containing any type.
Allen.
September 9th, 2008 at 8:11 am
Bob,
Yep, you’re right. In fact I did precisely this demo for the online demo of generics and anonymous methods.
Allen.
September 9th, 2008 at 8:16 am
Jim,
I could have recoded the VisualSwap function to directly access the FBox field, then replaced the call to VisualSwap with a call Syncronize() with an anonymous method that simply turns around and calls VisualSwap() directly. It would be the same effect.
The whole point of an anonymous method is that it automatically "closes around" the surrounding state so you don’t have to jump through some of these hoops. You can also think of them as nested functions/procedures that can occur right "in-place."
Allen.
September 9th, 2008 at 9:48 am
Good example, but it is interesting to know the "insides" of Delphi closure (anonimous method). What is it on binary level? What "calling conventions" for anonimous methods are?
September 9th, 2008 at 10:35 am
Serg,
You should follow Barry Kelly’s blog for more information about the internal implementation of a closure and what the compiler does to create this "magic." In future posts, Barry is planning on presenting some of the behind the scenes implementation of anonymous methods. http://barrkel.blogspot.com
Allen.
September 9th, 2008 at 4:34 pm
This was want I wanted to write to begin with. I am happy to see you now can. Congratulations on the new release!
Chuck.
September 9th, 2008 at 5:12 pm
Hey Chuck!
Thanks! Yeah, Anonymous Methods are going to open up a whole new world of programming idioms and paradigms. I think I like them just a little bit more than generics :-).
Allen.
September 9th, 2008 at 5:16 pm
[...] Allen writes a great article on a cool new use for Anonymous Methods in TThread. [...]
September 10th, 2008 at 11:00 pm
Nice "technology review"…
In that very specific case (!!), I’d suggest the use of a "KISS" convenient way
avoiding the use of a classic "synchronize" call:
procedure TSortThread.VisualSwap(A, B, I, J: Integer);
Begin
with FBox do
try
Canvas.LOCK;
…
Finally
Canvas.UNLOCK;
End;
End;
I can’t identify any drawback …
Alternative: Canvas.TRYLOCK;
September 11th, 2008 at 4:11 am
Briljant!
Guess the debugger steps through the statements as one might expect? Question: do anonymous methods support things like nested functions or even more declarations?
Another nice-to-have would be string-based methods with the anonymous-syntax:
procedure TSortThread.VisualSwap(A, B, I, J: Integer);
begin
Synchronize( ‘procedure ‘
+ ‘begin ‘
+ ‘ with FBox do ‘
+ ‘ begin ‘
+ ‘ Canvas.Pen.Color := clBtnFace; ‘
+ ‘ PaintLine(Canvas, I, A); ‘
+ ‘ PaintLine(Canvas, J, B); ‘
+ ‘ Canvas.Pen.Color := clRed; ‘
+ ‘ PaintLine(Canvas, I, B); ‘
+ ‘ PaintLine(Canvas, J, A); ‘
+ ‘ end; ‘
+ ‘end;’);
end;
Yes, I know this would involve JIT-compiling, but that’s exactly my point. Scripting has proven to be a way to popularize languages and right now it’s extremely cumbersome to build in scripting in a Delphi-application. Please please please make this a feature in Delphi asap.
Btw, thanks for your article,
Groetjes, Peter
September 11th, 2008 at 8:54 am
This is totally great! Much Kudos!
W
September 15th, 2008 at 3:20 pm
I’m puzzled. Why do you need a different overload of Synchronize to take a closure? Are closures represented by something other than the good-old tried-and-true TMethod? And if so, what’s the syntax for dealing with them?
September 19th, 2008 at 6:36 pm
cool!
d
September 19th, 2008 at 6:47 pm
joe> what oveload man? the closure passes to synchronize exactly what synchronize always expected…
September 26th, 2008 at 2:17 pm
Daniel, did you read the article? Allen said, "a new Synchronize overload was added to TThread that now takes a parameterless anonymous method."
So no, the closure does not pass to Synchronize exactly what Synchronize always expected. If it did, they wouldn’t have needed to add an overload.
And that prompted my question: is it not just a procedure of object? And if not, what’s the syntax?
September 26th, 2008 at 4:06 pm
[...] In this post I demonstrated how you can use an Anonymous Method to "synchronize" a background thread with the main UI thread. However there are times where you don’t want to block execution of the thread but still want to have something happen in the main UI thread, asynchronously. For several releases of Delphi there has been the Queue() method on TThread. This allows you to schedule a TThreadMethod (just like Synchronize) to execute on the main UI thread. The difference is that Synchronize will block the caller until the UI thread completes the call, while Queue will return immediately. The problem with the Queue() method is that there is no simple way to know when the "queued" event is done executing. Queue() really only works in a "queue it and forget it" scenario. It is still a form of Async programming has limited usefulness. New to D2009, a new Queue() overload was added just like Synchronize() that takes "reference to procedure" type (the underlying type to which you can assign an Anonymous Method). Let’s see if we can use the Queue() method as the underlying mechanism for doing some "A Sink" programming :-). [...]
September 27th, 2008 at 1:18 am
I agree, the way synchronize works/worked was tedious and this example will make the work of the programmer a bit easier.
I think it is noticeble that the examples of anonymous methods that make sense (or at least to me) all have to do with threads and the like. The anonymous methods in these examples are all used to create some sort of condition before executing code.
One begins to wonder: maybe there would be a (greater) need for a synchronize statement. If called from the UI thread, nothing happens. If called from another thread, the Synchronize mechanism kicks in…
procedure Foo;
begin
BeginSynchronize;
try
FBox.Canvas.Pen.Color := clBtnFace;
FBox.PaintLine(Canvas, FI, FA);
FBox.PaintLine(Canvas, FJ, FB);
FBox.Canvas.Pen.Color := clRed;
FBox.PaintLine(Canvas, FI, FB);
FBox.PaintLine(Canvas, FJ, FA);
finally
EndSynchronize;
end;
end;
September 27th, 2008 at 2:42 am
Bart - I agree with you. I sure they (the CodeGear guys) have something in the pipeline for simplifying use of multiple threads.
How about a keyword in declaration instead like:
procedure Foo; syncronized;
begin
// do some UI thing in the main thread…
end;
I sure that the folks in the R&D group can do that compiler magic just to follow your example, right ?
September 27th, 2008 at 2:55 am
@Per, that’s an even better solution I think. But I guess that synchronized keyword should be added in the prototype of the function, not in the implementation.
interface
procedure foo; virtual; synchronized;
implementation
procedure foo;
begin
end;
November 3rd, 2008 at 12:03 pm
[...] Allen Bauer blog post: "Retrofitting a classic" TThread demo with anonymous methods [...]