I have stumbled upon an unexpected Delphi 2009 behaviour. After investigating a strange bug in my code, I managed to narrow down the issue and create a minimal example which I present below.
Of course, the following code prints the value 1:
program Example1;
{$APPTYPE CONSOLE}
type
TIntFcn = reference to function(const X: integer): integer;
function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
result := AFunction(a);
end;
begin
writeln(fcn(function(const X: integer): integer
begin
result := 1;
end, 0));
end.
Similarly, this program prints the value 2:
program Example2;
{$APPTYPE CONSOLE}
type
TIntFcn = reference to function(const X: integer): integer;
function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
result := AFunction(a);
end;
begin
writeln(fcn(function(const X: integer): integer
begin
result := 2;
end, 0));
end.
"Obviously", this third program prints the same value as the first one, namely, 1:
program Produce;
{$APPTYPE CONSOLE}
type
TIntFcn = reference to function(const X: integer): integer;
function fcn(AFunction: TIntFcn; a: integer): integer; inline;
begin
result := AFunction(a);
end;
begin
writeln(fcn(function(const X: integer): integer
begin
result := 1;
end, 0));
fcn(function(const X: integer): integer
begin
result := 2;
end, 0); // discard the output
end.
However, the output isn't 1, but 2. It seems like the compiler uses the second anonymous function in the call to fcn
in writeln
.
To me this seems like a bug in the Delphi 2009 compiler, but it could also simply be my not understanding the more subtle details about anonymous functions in Delphi. What do you think?
This certainly appears to be a bug, and according to the comments received on the question, this has been fixed in Delphi XE. Probably the simplest workaround is to skip asking for inlining if the compiler cannot handle it correctly:
program Solve;
{$APPTYPE CONSOLE}
type
TIntFcn = reference to function(const X: integer): integer;
function fcn(AFunction: TIntFcn; a: integer): integer;
{$IF CompilerVersion >= 22}inline;{$IFEND} {Warning: Horrible bug in Delphi 2009}
begin
result := AFunction(a);
end;
begin
writeln(fcn(function(const X: integer): integer
begin
result := 1;
end, 0));
fcn(function(const X: integer): integer
begin
result := 2;
end, 0); // discard the output
end.
In most cases, the loss of performance should be negligible in Delphi 2009, and you do request inlining in XE and later. Of course, if you don't think inlining is important at all, you can simply remove the request altogether.