Anonymous methods (aka Closures) are rare visitors in Delphi code. I have upgraded to Delphi 2009 a year before and never used the anonimous methods. But last week it finally happened.

I was writing the unit tests for fast fourier transform code. The idea of some tests was to compare the results of fast fourier trasform and discrete fourier transform of arbitrary function, and it appeared that the anonymous method is the best way to pass the function to the test.

type TRealFunc = reference to function(N: Integer): Extended; type TTestFFT = class(TTestCase) private procedure TestRealFunc(Func: TRealFunc; Count: Integer); published procedure TestRealFFT00; ... end;

All checks are done within TestRealFunc procedure. It receives a function to transform as an argument, makes fourier transform of the function using two different methods and compares the results:

procedure TTestFFT.TestRealFunc(Func: TRealFunc; Count: Integer); var FFTData: array of Extended; DFTData: array of TksComplex; M, N: Integer; Arg: TksComplex; begin SetLength(FFTData, Count); SetLength(DFTData, Count); for M:= 0 to Count - 1 do begin FFTData[M]:= Func(M); // discrete Fourier transform; DFTData[M]:= 0; for N:= 0 to Count - 1 do begin Arg.Re:= 0; Arg.Im:= (2 * Pi * N * M) / Count; DFTData[M]:= DFTData[M] + Func(N) * TksComplex.Exp(Arg); end; end; // fast Fourier transform RealFFT(@FFTData[0], Count, False); CheckEquals(FFTData[0], DFTData[0].Re, 1E-15); CheckEquals(FFTData[1], DFTData[Count shr 1 - 1].Re, 1E-15); CheckEquals(0, DFTData[0].Im, 1E-15); CheckEquals(0, DFTData[Count shr 1 - 1].Im, 1E-15); for N:= 1 to Count shr 1 - 1 do begin CheckEquals(FFTData[2 * N], DFTData[N].Re, 1E-15); CheckEquals(FFTData[2 * N + 1], DFTData[N].Im, 1E-15); CheckEquals(FFTData[2 * N], DFTData[Count - N].Re, 1E-15); CheckEquals(FFTData[2 * N + 1], - DFTData[Count - N].Im, 1E-15); end; end;

The test procedures themselves just calls the TestRealFunc with different arguments. For example,

procedure TTestFFT.TestRealFFT00; begin TestRealFunc( function(N: Integer): Extended begin Result:= Sin(pi / 4 * N) + 0.5 * Sin(pi / 2 * N + 3 * pi / 4); end, 8 ); end;

Though the syntax looks cumbersome, the solution based on anonimous methods is very logical.