Anonymous Methods and Closures
Anonymous methods are reference counted interfaces under the hood. Captured variables are shared by reference.
Used heavily with TThread.Queue/Synchronize, TTask.Run, TParallel.For, sorting comparers, REST async callbacks, and timers.
Pitfall: capturing loop variables. All closures see the final value. Capture through a helper function to get a per-iteration copy.
type
TIntFunc = reference to function(X: Integer): Integer;
TProc = reference to procedure; // TProc, TProc<T>, TFunc<TResult>, TFunc<T, TResult>, TPredicate<T> exist in System.SysUtils
function MakeMultiplier(Factor: Integer): TIntFunc;
begin
Result := function(X: Integer): Integer
begin
Result := X * Factor; // captures Factor (closure)
end;
end;
function MakeCounter: TFunc<Integer>;
var
Count: Integer;
begin
Count := 0;
Result := function: Integer
begin
Inc(Count); // captured variable lives on after MakeCounter returns
Result := Count;
end;
end;
procedure ForEach(const Items: TArray<string>; const Action: TProc<string>);
begin
for var Item in Items do Action(Item);
end;
var Triple := MakeMultiplier(3);
Writeln(Triple(10)); // 30
var Counter := MakeCounter;
Writeln(Counter, ' ', Counter); // 1 2
ForEach(['a', 'b'], procedure(S: string) begin Writeln(S.ToUpper); end);
var IsEven: TPredicate<Integer> := function(N: Integer): Boolean begin Result := not Odd(N); end;