Tuesday, September 30, 2008

A simple Generic Dictionary: TDictionary

A new generic type in Delphi 2009 is TDictionary. TDictionary offers a way to store values based on a key into a list. TDictionary is declared as TDictionary<TKey, TValue>.
TDictionary in fact is what a hashtable is in C#. It allows you to store/structure data based on any key type and any value type.

Suppose we want to track our persons, from the previous blogpost, on their social security number, we could put them in TDictionary like this: (using a very simple social security number....)

procedure TForm4.Button2Click(Sender: TObject);
var
Dic : TDictionary
<Integer,TPerson>;
p : TPerson;
i : integer;
begin
//Create dictionary
Dic := TDictionary<Integer,TPerson>.Create;
Dic.Add(
1, TPerson.Create('Delphi', 'Mr'));
Dic.Add(
2, TPerson.Create('Generic', 'Bill'));
Dic.Add(
3, TPerson.Create('nonymous', 'An'));
try

//Travel the strings
for p in Dic.Values do begin
ShowMessage(p.FullName);
end;

//Travel the keys
for i in Dic.Keys do begin
ShowMessage(IntToStr(i)
+ ': ' +
Dic.Items[i].FullName);
end;

//Find some key
if Dic.TryGetValue(3, p) then begin
ShowMessage(
'Found it!: ' + p.FullName);
end;

finally
for p in Dic.Values do
p.Free;

//Also free Values and KeyCollection
//other wise you have a memoryleak
//Is this a bug?
Dic.Values.Free;
Dic.Keys.Free;

//Free the dictionary
Dic.Free;
end;

I noticed that if you free the Dictionary in above scenario you must also free the Values and Keys collection to avoid a memory leak. This looks like a bug to me. (Will investigate this further)

In this sample I used an integer type as the key value, so this has not much benefit compared to an array. You can however use any type to be the key value!

Because we can store any type, we can take this a step further and put a TList<T> in our Dictionary:

Suppose we want to put our Personlist into a dictionary based on, let's say their gender. You could do that something like this:


type
PersonKind
= (pkMale, pkFemale);

procedure TForm4.Button3Click(Sender: TObject);
var
Dic : TDictionary
<PersonKind,TList<TPerson>>;
MPersonsList : TList
<TPerson>;
FPersonsList : TList
<TPerson>;
pList : TList
<TPerson>;
p : TPerson;

begin
MPersonsList :
= TList<TPerson>.Create;
FPersonsList :
= TList<TPerson>.Create;
Dic :
= TDictionary<PersonKind,TList<TPerson>>.Create;
try
//Fill male list
MPersonsList.Add(TPerson.Create('Delphi','Mr'));
MPersonsList.Add(TPerson.Create(
'Generic','Bill'));
MPersonsList.Add(TPerson.Create(
'Nymous','Ano'));
//Fill female list
FPersonsList.Add(TPerson.Create('Delphi','Mrs'));
FPersonsList.Add(TPerson.Create(
'Nymous','Anna'));
//Add to dictionary
Dic.Add(pkMale, MPersonsList);
Dic.Add(pkFemale, FPersonsList);

//Travel
for p in Dic[pkMale] do begin
ShowMessage(
'This is a man: ' + p.FullName);
end;
for p in Dic[pkFemale] do begin
ShowMessage(
'This is a female: ' + p.FullName);
end;
finally
//Free Persons and Personlist
for p in MPersonsList do p.Free;
for p in FPersonsList do p.Free;
MPersonsList.Free;
FPersonsList.Free;

Dic.Free;
end;
end;

TDatadictionary is a very powerfull, yet in basic easy to use, generic type. It allows you to build simple, but also complex data structures. (What about a TDictionary with TDictionary's in it? ;-) )

Again a very nice language addition to Delphi!

Thursday, September 25, 2008

A simple Generic List: TList<T>

Delphi 2009 has support for generics, and has 'built in' generic types like TList, TArrays etc. If you want to use them you must add Generics.Collections to your uses clause.

Generic List: TList
Suppose we want a list with persons representing the TPerson class:

// Our class TPerson
type
TPerson
= class
FFirstName : string;
FLastName : string;
private
function GetFullName: string;
published
public
constructor Create(ALastName : String;
AFirstName : string);
property FirstName : string read FFirstName
write FFirstName;
property LastName : string read FLastName
write FLastName;
property FullName : string read GetFullName;
end;

//Define the generic list
PersonsList : TList<TPerson>;

//Method to fill the list
procedure TForm4.btnPopulateClick(Sender: TObject);
begin
//Filll the personslist
PersonsList.Add(TPerson.Create('Delphi','James'));
PersonsList.Add(TPerson.Create(
'Generic','Mister'));
PersonsList.Add(TPerson.Create(
'Anon', 'Method'));
//etc.
end;

//Traveling this list to fill a TListBox
procedure TForm4.FillListBox;
var
p : TPerson;
begin
ListBox1.Items.Clear;
for p in PersonsList do begin
ListBox1.Items.Add(p.FullName);
end;
end;

As you can see, no rocking science needed to implement a generic list!

Sorting a generic TList
The next step is to implement a sorting method to sort the list on, for example, the Lastname property.

A TList has a Sort property which has an IComparer interface that can be implemented like this using an anonymous method:

(You will have to add generics.default to your uses clause)
procedure TForm4.btnSortClick(Sender: TObject);
begin
PersonsList.Sort(TComparer
<TPerson>.Construct(
function(const Item1,Item2:TPerson): Integer
begin
Result :
=
CompareText(Item1.LastName, Item2.LastName);
end));
end;

Generics is a great new feature of Delphi 2009. Just as in C# you will use them all the time. In this context, the use of anonymous methods is great.

Besides TList Delphi has more standard generics typs including TArray, TEnumarable and more, so there is always more to explore!

Update 25-09-2008 10:58
As animal commented you must of course create the list first, which I did not include in the code snippets.

PersonsList:= TList.Create;

And you will have to free it also at sometime. (Don't forget to free the TPerson objects as well!)

for p in PersonsList do begin
p.free;
end;
PersonsList.Free;

Monday, September 22, 2008

"Cast on News" episode at Delphi.org

Last Friday I had a really fun experience, because Jim McKeeth invited me to be on the sixth episode on The Podcast at Delphi.org - "Cast on News." 

Also invited were marc hoffman from Remobjects, and Jolyon Smith from the Te Waka o Delphi blog. Together with host Jim McKeeth we talked about the new Delphi 2009 and Delphi in general. It turned out to be a good and fun talk.

'Speaking up' instead of 'Writing up' is a total different experience, I can tell you now ;-).  Make sure you don't miss it, you can 'hear' this podcast on the Delphi.org website.

Sunday, September 21, 2008

Those tiny little details...

It are the tiny little details that makes a new release so interesting.
Take for instance the code completion popup window of Delphi 2009, it now shows deprecated functions and properties in the color dark gray.

Tuesday, September 16, 2008

Delphi 2009 very first impressions

Today the SA announcements finally hit the doorstep. Here are some very first impressions:

1. Installation
Installation improved a lot! Installing Delphi 2009, so not C++ Builder, only took 13 minutes.
The installation of the documentation, which is a separate install took about 17 minutes.

2. First startup
Start up time (cold) is on my machine approx. 10 seconds. A warm start however only takes 6 seconds. (Personally I don't care a lot about startup times, at least as it does not take too long ;-), but is a nice measure point)

My machine: Intel Core 2 duo 1,86 Ghz. 2GB Ram, Windows Vista Business.

So the installation experience is a lot better then before. (remember > 1 hour installations...).
For my real projects I will have to wait for Devexpress, who are now working on Delphi 2009 support, before I can upgrade, but I guess until then there is a lot to explore.....generics, unicode....etc. By the way, Dr Bob has this nice overview with lots of blogpost and resources about Delphi 2009.

Use an image as your UIBarButtonItem

Using an image as your UIBarButtonItem in your navigationcontroller bar can only be achieved by using a common UIButton as the BarButtonItem...