First of all, I'm not sure if FPC fully supports closures now.
As mentioned in the link provided by
Bogen85, yes, it does since end of May.
Second thing - Delphi is considered to be standard and it throws the same error. Because, I guess, Nested relies on Main's stack frame, so it can be called from Main only.
Third thing - Delphi throws the same error for your second program too. I don't know, why it works for you. It shouldn't. Because it's exactly the same situation.
FPC supports a bit more functionality than Delphi does. E.g. assigning a nested function to a function reference is perfectly fine, because the compiler can rework the code so that it will work.
This should be internally compiled into exactly the same:
tcf := procedure(const n: integer)
begin
nested(n);
end;
Not quite. If you assign a nested function to a function reference the end result will essentially be this:
procedure main;
type
tSimpleProc = interface
procedure Invoke(const n: integer);
end;
TCapturer = class(TInterfacedObject, tSimpleProc)
x: integer;
procedure nested(const n: integer);
procedure tSimpleProc.Invoke = nested;
end;
procedure tSimpleProc.Invoke(const n: integer)
begin
writeln ('Hello from nested! ', n, ' x: ', x);
inc(x);
end;
var
capturer: TCapturer;
capturer_keepalive: IUnknown;
procedure nested(const n: integer);
begin
capturer.nested(n);
end;
var
tcf: TSimpleProc;
begin
capturer := TCapturer.Create;
capturer_keepalive := capturer;
tcf := capturer as tSimpleProc;
end;
Essentially it moves the code of the original nested function into a method of the capturer class and has the nested function call that instead. This allows the nested function to be used as a function reference and as a nested function at the same time.
You should understand, how closures work. Your program is turned into:
type
//There is no such thing, but, I guess, you get this idea
//It's:
//tSimpleProc = record
// Intf:IInterface
// Proc:procedure;
//end;
//When it's called - it's something like tcf.Proc(tcf.Intf, ...);
//I.e. tcf.Intf is passed as Self
tSimpleProc = procedure of interface;
Not
quite. There is no concept of “
procedure of interface”, instead a “
reference to procedure” is turned into an
interface with a single method
Invoke. You can see this, because you can manually
implement a function reference in a custom class just like an ordinary interface or you can even
inherit from it.
1) Temp variables are created implicitly, when procedure/function types are used instead of closures - they're captured instead of procedures/functions themselves (Delphi incompatible)
It's not “Delphi incompatible”, because Delphi-compatible code still works. However it's an
enhancement to what Delphi allows.
2) Unassigned closure is treated as simple nested procedure/function
An unassigned anonymous method works in Delphi as well (as long as you only capture stuff that Delphi supports
). Delphi however converts that to a method of the capturer object nevertheless and calls it. FPC is a bit more cheap here and simply calls it like a nested function, cause for the user it will have the same effect.
This does not work, a direct capture of nested procedure.
I had not thought about that use case, but in essence it should be possible as well, considering that it works when assigning a nested function. Please do a feature request on our
bug tracker.