Modern Object Pascal includes features common in other advanced languages to enhance code safety, flexibility, and readability.
1. Generics (Type-Safe Reusability)
Generics allow you to write classes, interfaces, and methods that operate on types specified by the user at the point of consumption. This provides strong type safety while maintaining maximum code reuse.
- Problem Solved: Before generics, if you wanted a list of
Integers and a list ofStrings, you had to write separate collection classes or use non-type-safe methods (likeTObjectList) that required explicit type casting everywhere.
A. Generic Declaration
The type parameter is represented by an identifier (often T for Type) enclosed in angle brackets (< >).
// Example: A generic stack class
type
TMyStack<T> = class(TObject) // T is the placeholder for the type
private
fItems: TList<T>; // Uses the built-in generic list
public
constructor Create;
procedure Push(const Value: T); // Value must be of type T
function Pop: T;
end;
B. Generic Instantiation
When you use the generic class, you specify the concrete type you want the placeholder T to represent.
// In a procedure:
uses
System.Generics.Collections; // Required for TList<T>
var
IntegerStack: TMyStack<Integer>; // Type T is Integer
StringStack: TMyStack<String>; // Type T is String
begin
IntegerStack := TMyStack<Integer>.Create;
StringStack := TMyStack<String>.Create;
IntegerStack.Push(42);
// IntegerStack.Push('Hello'); // Compile-time error! (Type Safety)
StringStack.Push('World');
IntegerStack.Free;
StringStack.Free;
end;
C. Built-in Generic Collections
The most common use of generics in Delphi is with the System.Generics.Collections unit, which provides ready-to-use type-safe collections:
TList<T>: The standard dynamic, indexed list of typeT.TDictionary<K, V>: A hash table (key-value store) where the Key (K) and Value (V) are both strongly typed.TObjectList<T: class>: A list specifically for objects, which can automatically manage memory (destruction) when the list is cleared or the item is removed.
2. Anonymous Methods (Inline Functions)
An Anonymous Method is a procedure or function that is declared and defined inline at the point where it is used, without a formal name or entry in the unit’s interface.
- Purpose: They are primarily used as event handlers or callbacks for tasks like threading, parallel processing, or asynchronous operations, leading to cleaner code where the logic is immediately apparent.
- Closure: Anonymous methods form a closure, meaning they can access and modify local variables from the scope in which they were created (the outer function).
Syntax
Anonymous methods use the keywords procedure or function followed by optional parameters, and then the standard begin...end block.
// Declaration of a variable to hold the anonymous method reference
type
// Defining a generic type for a parameter-less procedure
TMyProcedure = reference to procedure;
procedure TForm1.SetupTimer;
var
Counter: Integer; // Local variable captured by the closure
begin
Counter := 0;
// Assign an anonymous method to an event/variable
Timer1.OnTimer := procedure
begin
// Accesses and modifies the local 'Counter' variable (Closure)
Inc(Counter);
lblCounter.Caption := IntToStr(Counter);
if Counter >= 10 then
Timer1.Enabled := False;
end;
Timer1.Enabled := True;
end;
Anonymous Function with Return Value
If the anonymous method is a function, the return type is placed after the parameter list (or simply after function if no parameters are used). The return value is set using the Result variable.
// Type definition for a function that returns an Integer
type
TValueFunction = reference to function: Integer;
procedure TForm1.UseAnonymousFunction;
var
// Assign the anonymous function to the variable
GetRandom: TValueFunction;
RandomValue: Integer;
begin
GetRandom := function: Integer
begin
Randomize;
Result := Random(100);
end;
RandomValue := GetRandom; // Call the anonymous function
ShowMessage(IntToStr(RandomValue));
end;
