www.destructor.de
You may ask yourself, why I publish this code. In fact, I have been asked more than once why I use TLinkList at all. Since Delphi 5, there is a unit Contnrs which contains the TObjectList class which does about the same as TLinkList, especially if you pass the constructor nothing or a TRUE, which means that the list owns its items. Which means that a .Delete or .Free will also destroy the items.
There are some things which make TLinkList better suited for the vast majority of my programming work. Here they are:
A modern object-orientied application is not a collection of modules and their routines. It is a "world" of interacting objects. To keep these objects, to give them structure, you must put them into containers.
I am programming with Turbo Pascal and Delphi since 1987. In writing thousands and thousands of lines of code over these years, I can firmly state that at least in 99 % of all cases, lists are always scanned sequentially, i.e. skipping from one node to the next. It is very rare that you need random access (via an index) to the list nodes.
So why do we have so much arrays then? Because arrays are simple to teach and learn. And in early BASIC it was the only available container at all.
An ObjectList is an array of pointers to objects. When it gets longer, you must re-allocate the memory for this pointer-list, copy all pointers to the new buffer and dispose of the old list. There may be memory limitations for the pointer list (OK, in a 32-bit world these are admittedly high, but in DOS and 16-bit Windows, a list could only handle 16K pointers).
A LinkList can grow as long as there is memory available. The time needed for the addition of a node is always the same.
Suppose we have a list and we want to call DoSomething (Node : TElement) and DoSomeOtherThing (Node : TElement) for every node in the list (remeber? Scanning lists from beginning to end is the most common access method needed).
VAR
i : integer;
Node : TElement; BEGIN
FOR i := 0 TO List.Count - 1 DO BEGIN
Node := TElement (List [i]);
DoSomething (Node);
DoSomeOtherThing (Node);
END;
END;
VAR
Node : TElement;
BEGIN
List.StartScan (Node);
WHILE List.Scan (Node) DO BEGIN
DoSomething (Node);
DoSomeOtherThing (Node);
END; END;
In the TLinkList code, there is no need for:
TLinkList iterations are simpler to program and, more importantly, less to type.
That's why I prefer TLinkList over TObjectList. Except in those seldom cases where a TObjectList is better. (But hey, there are also those (very, very, very, very, very) seldom cases where a GOTO comes in handy ... :-)