It's quite an interesting one. For whatever reason, the compiler treats Result
differently from other variables. I see no good reason for that, so this feels like a compiler bug.
I see a few workarounds:
- Declare a local variable, use that, and finish the function by assigning that local variable to
Result
. - Using parens to call the function:
Result().Add('abc')
. - Using a better smart pointer. For instance, a smart pointer that is not based on method invocation would be a good start. A generic record with an implicit conversion operator would presumably work.
- Find a version of the compiler without the bug, if indeed it is a compiler bug.
- Give up on smart pointers and write traditional style code. Every time I contemplate using smart pointers in Delphi I conclude that I'd rather see the explicit try/finally blocks and understand when my objects are created and destroyed.
FWIW, you can greatly simplify the issue by stripping out the smart pointer code, and removing the generic types. Here is the cleanest SSCCE that I can concoct:
{$APPTYPE CONSOLE}
type
TFunc = reference to function: TObject;
procedure Foo;
var
F: TFunc;
begin
F.ClassName; // compiles
end;
function Bar: TFunc;
begin
Result().ClassName; // compiles
Result.ClassName; // [dcc32 Error] E2003 Undeclared identifier: 'ClassName'
end;
begin
end.
I'm now convinced that this is a compiler bug.
It is presumably related to the rather unusual language feature of Delphi that means the function call parentheses can be omitted for a function that has no parameters. This convenience sometimes brings with it ambiguity. However, in this case there is no ambiguity. The .
operator has no meaning when applied to a TFunc<TObject>
and so the only way to interpret these statements is that the function is called, and the .
operator applied to the returned value.
Bug report: QC123218.