Modern Object Pascal supports features that allow for highly flexible, safe, and concise code. Generics solve the problem of type safety in collections, and Anonymous Methods simplify asynchronous programming and event handling.
1. Generics (Type-Safe Reusability)
Generics allow you to define classes, interfaces, or routines with placeholders for the types they operate on. This means you can create a single list implementation that works correctly and safely for Integers, Strings, or any custom TObject type, without having to write separate code for each.
- Benefit: Eliminates the need for manual type casting and prevents runtime errors caused by mixing types (type safety).
- Syntax: Generic types are specified using angle brackets (
<T>,<K, V>, etc.), whereTis a placeholder for the actual type.
A. Declaration and Usage
program GenericsDemo;
// 1. Declaration of a Generic Class
type
// TItem is the generic parameter (placeholder)
TBox<TItem> = class
private
fValue: TItem;
public
property Value: TItem read fValue write fValue;
// Method uses the generic type
function GetDescription: String;
end;
implementation
function TBox<TItem>.GetDescription: String;
begin
Result := 'Box containing type: ' + TItem.ClassName;
end;
// 2. Usage (Instantiation)
var
IntegerBox: TBox<Integer>; // A Box guaranteed to hold only Integers
StringBox: TBox<String>; // A Box guaranteed to hold only Strings
begin
IntegerBox := TBox<Integer>.Create;
StringBox := TBox<String>.Create;
IntegerBox.Value := 42; // OK
// IntegerBox.Value := 'Hello'; // ERROR: Compiler prevents this mixed type assignment!
Writeln(IntegerBox.GetDescription);
IntegerBox.Free;
StringBox.Free;
end.
B. Standard Generic Collections
The most common use of generics is with built-in collection classes, such as:
TList<T>: A dynamic, type-safe list (like a dynamic array, but managed by a class).TDictionary<K, V>: A key-value pair map where both the Key (K) and the Value (V) are type-safe.
uses Generics.Collections; // Required unit for standard generics
var
Names: TList<String>; // A list guaranteed to hold only strings
Ages: TDictionary<String, Integer>; // Key is String, Value is Integer
begin
Names := TList<String>.Create;
Ages := TDictionary<String, Integer>.Create;
Names.Add('Alice');
Ages.Add('Alice', 30);
Writeln('Alice is ', Ages.Items['Alice'], ' years old.');
Ages.Free;
Names.Free;
end.
2. Anonymous Methods (In-Line Code)
An Anonymous Method is a procedure or function that is declared and defined in-line at the point where it is used, and it does not have a name.
- Benefit: Allows code to be treated as data. They are crucial for writing compact event handlers, multi-threading callbacks, and functional programming constructs (like map, filter, reduce).
A. Declaration and Syntax
Anonymous methods use the procedure or function keyword followed immediately by the begin...end block, often wrapped in a variable or passed directly as a parameter.
program AnonymousMethodDemo;
type
// 1. Definition of a Procedure type that takes one Integer (for variable storage)
TIntProc = reference to procedure(AValue: Integer);
var
MyCallback: TIntProc;
begin
// 2. Assign the anonymous method to the variable
MyCallback := procedure(AValue: Integer)
begin // No name, definition is right here
Writeln('The value received is: ', AValue);
Writeln('Running callback code...');
end; // Assigned to the variable
// 3. Execute the anonymous method via the variable
Writeln('Before callback.');
MyCallback(99);
Writeln('After callback.');
end.
B. Closure (Accessing Outer Variables)
A powerful feature of anonymous methods is Closure. The method retains access to all local variables declared in the surrounding routine’s scope, even after that routine has finished executing.
procedure OuterRoutine;
var
Counter: Integer; // Local variable of OuterRoutine
AProc: TIntProc;
begin
Counter := 10;
AProc := procedure(AValue: Integer)
begin
// The anonymous method closes over (captures) the 'Counter' variable
Counter := Counter + AValue;
Writeln('New Counter value: ', Counter); // 10 + 5 = 15
end;
AProc(5); // Executes the anonymous method
// Counter still exists and holds 15!
end;
Real-World Use: This is essential for modern event handling and multi-threading, allowing a background thread to safely call an anonymous method that updates the main thread’s UI, while automatically having access to the needed local data.
