So, the first object that descends from TObj (and is already used in the TObj object itself to store a list of objects and methods for automatic destruction) is TList. It can store arbitrary pointers or 32-bit numbers (which is why it is called a "universal" list).
In Delphi (both VCL and KOL), a list is not just a single or doubly linked list of pointers, but rather an array of pointers. The advantages of an array over a linked list are obvious: great speed of work when you need to quickly access the elements of the list by index. Memory is also consumed more economically: in the case, for example, of a doubly linked list, along with each pointer, you would have to store pointers to the previous and next elements in the list, and allocate your own memory fragment in the heap for this triplet, adding 8 more bytes of overhead per item.
Unfortunately, the array list also has disadvantages when compared to a simple doubly linked list. Namely, since the number of pointers for storage is usually unknown in advance, increasing the size of the array leads to its reallocation in memory, and very often - to moving the entire accumulated array to a new location. With small sizes of lists, this circumstance can be neglected, but if the number of elements reaches several thousand, you need to think about optimizing performance.
For this, there is the Capacity property, which determines how many items in the list will be allocated memory. If the size of the list (the Count property is the current size of the list) exceeds the Capacity value, it is recalculated according to some simple algorithm, which is chosen as a reasonable compromise between saving reserved memory and optimizing program speed by reducing the number of memory reallocations for an array of pointers. By default, the recalculation consists in increasing the reserved size by AddBy, initially equal to 4, but if the AddBy property is set to 0, then the increase occurs immediately by 25%, but not more than 1000. Of course, this algorithm cannot be good for all occasions. ,
The main property of the TList object is Items [i], which provides access to list items by index. For example, a typical loop of enumerating all the elements of a list from first to last is not much different from what is done in the VCL:
var L: PList; i: Integer; P: Pointer;
...
for i: = 0 to L. Count-1 do
begin
P: = L. Items [i];
... // working with P
end;
Note (once again, it was already mentioned above) that the short form P: = L [i] is not available, because objects object, unlike classes, cannot have default properties (which is a pity, for example, I do not see any point in such a restriction, except for the lack of desire on the part of Dephi developers to provide this convenient service).
Another significant difference from the VCL is how the TList object type is instantiated. If in VCL we wrote:
var L: TList;
...
L: = TList.Create;
then in KOL you should write differently:
var L: PList;
...
L: = NewList;
Now I will give the main set of methods and properties of TList, in addition to those already mentioned:
Add(P) - adds a pointer to the end of the list;
Insert(i, P) - inserts a pointer at position i (all previous elements starting from i, if any, are shifted one position up);
Delete(i) - removes one element with index i (all elements with index i + 1, if any, are shifted one position down);
DeleteRange(i, n) - fast deletion of n elements from position i (it is allowed to specify as n a greater value than there are elements starting from position i, i.e. DeleteRange (i, MaxInt) - will delete all elements starting from index i);
Remove(P) - finds and removes the first occurrence of the pointer P;
Clear - clears the list, removing all pointers from it;
IndexOf(P) - finds the first occurrence of the pointer P and returns its index (or -1 if there is no such pointer in the list);
Last - returns the last pointer in the list, equivalent to Items [Count-1];
Swap(i1, i2) - swaps pointers with indices i1 and i2;
MoveItem(i1, i2) - removes an element from position with index i1 and inserts it into position with index i2;
Release - can be used to destroy the list of pointers to memory areas allocated in the heap (by the GetMem or AllocMem, ReallocMem functions), beforehand for all non-null pointers, FreeMem is called;
ReleaseObjects - similar to the previous procedure, but used for a list of pointers to objects: all objects in the list are destroyed by calling the Free method;
AddItems(a) - allows you to add an array of pointers at once;
Assign(L) - assigns to the list the elements of another list, i.e. simply copies an array of pointers;
DataMemory - returns the current pointer to the internal array of pointers that make up the list (you should use it with caution, and only if you need to significantly optimize the speed of access to the elements of the list).
Comment: KOL also has an object type TListEx (but it is moved to the additional module KOLadd.pas, for reasons of saving the number of lines in the main module KOL.pas, and because there is no strict need to use it). In addition to the properties and methods of TList, it has a property Objects [i], methods AddObject (P, o), InsertObject (i, P, o) and others - allowing you to associate another "object" -number with each element of the list, or pointer. In fact, there is no special need for such an object, and it is often enough to use the same TList, storing pairs of values in it and assuming that each even element, together with the next odd one, form an inseparable bundle.