Wednesday, October 08, 2008

Fun with Generics.collections

I guess the best way to learn about new language features are to put them in practice, and with that I jumped into using the TDictionary to keep track of some xml nodes I was editing.  It was very easy to implement, but what got me stumped was then how to iterate thru the entire list and apply changes to all of the nodes at once.

Thats when I recalled the new for ... in ... syntax.  Using it was dirt simple.  Since my collection was created as tDictionary all I had to do was create a new variable of tPair and then use the for..in.. syntax to invoke a body of code against every IXmlNode in my tDictionary.


var
aPair : tPair<string,ixmlnode>
begin
for aPair in fDictionary do
aPair.Value.Attributes['dirty'] := '-1';
end;

In my option, this generates code which is much more readable and feels more natural.  Now, on to the next challenge.... finding a place in my project where I can put annoymous methods to practical use.

(EDIT: Updated syntax on variable declaration, as it was incorrect...seems the problem with generics is that they HIDE when copied to HTML.)

Tuesday, September 02, 2008

Google Chrome now available

Download and play with it now. http://tools.google.com/chrome/?hl=en-US

Very small footprint, very fast browser.

First look, browser has much more room compared to IE/Firefox out of the box....although my webmail provider (not Gmail of course) doesn't recognize the browser yet so it doesn't give me the rich experience I'm used too.

Sunday, October 21, 2007

Sychronizing source code directories

One of the big problems I have faced by using Vista Ultimate on my primary development machines as a host OS for virtual PC development environments has been the fact that Vista Ultimate (and I am assuming other versions of Vista as well) have problems copying extremely large files. It was part of this frustration that led us to develop AngeliaSync, a folder synchronization utility which does an excellent job of maintaining synchronized folders.

If you are looking for an inexpensive and easy to use backup utility, why not give AngeliaSync a try?

http://www.kamradtandhill.com/angeliasync.asp

Tuesday, August 22, 2006

Avoiding circular refrences

Sometimes its the simple things that make it all worth while. As I once again took out my fork and began to separate out a huge pile of spaghetti code that was left for me, I needed to come up with a better method to avoid the circular reference trap. I had several units which contained classes which were directly referencing the main form. The circular reference here was troubling me as if I needed to pull one of the units out for another project, the entire application would go along with it.

My solution turned out to be quite simple. I created a new interface unit which contained nothing more than a set of interfaces:

unit MyProgram_Intf;
interface
// ---------------------------
type
iMainGui = interface
['{3D8EC075-0A0D-438E-9BCD-9BDDE10112E8}']
procedure SetStatus(sStatusMsg:String;iProgress:Integer);
end;

iMyModule = interface
['{A6A09A36-C4F2-4E2E-B231-B51A948FE4D4}']
procedure SetMainGui(pMainGui:iMainGui);
function PerformTask : boolean;
end;
//----------------------------
implementation
end.

After saving this unit and adding it to my main form and my child forms, I then changed each child form unit to something like:

tModuleOne = class(tForm,iMyModule)
private
fMainGui : iMainGui;
procedure SetMainGui(pMainGui:iMainGui);
function PerformTask:boolean;
end;

The implementation of SetMainGui is very simple:

procedure tModuleOne.SetMainGui(pMainGui:iMainGui);
begin
fMainGui := pMainGui;
end;

After adding the implmentation for each of these two methods, I added the following code to the initialization section of the unit (replacing tModuleOne with the name of the form class for this unit):

initialization
register(tModuleOne);
end.

Next I removed each one of the units from the main form to force myself to only use the interface. I implemented the SetStatus routine in the main form. The only thing left was the method to invoke each item. I ended up with the following:

function tMainForm.InvokeTask(sTaskname:String):boolean;
var
fTaskClass : TCustomFormClass;
fTask : tCustomForm;
fModule : iMyModule;
begin
Result := false;
try
fTaskClass := tCustomFormClass(FindClass(sTaskname));
except
// an exception here signals the class was not found
exit;
end;
fTask := fTaskClass.Create(nil);
try
if not Supports(fTask,iMyModule,fModule) then
begin
// if we get here then the module
//doesn't support the correct interface
exit;
end;
fModule.SetMainGui(Self);
result := fModule.PerformTask;
finally
fModule := nil;
fTask.Free;
end;
end;


Then, when I needed to call one of the tasks, I just called the InvokeTask method passing it the name of the class I needed to use. No more direct circular refrences, and each unit could easily be picked up and dropped into another project only requiring the unit with the interfaces is brought along also.