First of all, I'm not sure if FPC fully supports closures now.
@VTwin
Function references encapsulates the function together with it's lexical context (at least - part of) which is also knows as a "closure" (C#, C++). May be the most familiar example in FPC is the method delegate (procedure of object), which keeps together the method address and the Self pointer of the instance it belongs. Thus, the receiver object can execute the method in the context of the original object.
Function references just broadens the context by being able to keep it bigger - including variables from the current scope, etc.
But the devil is into the details, and I wonder how useful it will be in practice considering the dynamic nature of the class instances in FPC.
From what I can tell, FPC (built from latest git, does support closures).Great news then. My Delphi project relies on this feature. I guess, it has been last FPC's incompatibility with modern Delphi versions. I'll try to compile my project via FPC, when I'll have time to do it.
I was playing around them and they definitely work as if they are closures (I did various things where I passed them off into various contexts and they worked as expected for closures), which is how I discovered the above behavior.
First of all, I'm not sure if FPC fully supports closures now.
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.
This should be internally compiled into exactly the same:
tcf := nested;
tcf := procedure(const n: integer) begin nested(n); end;
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;
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)
2) Unassigned closure is treated as simple nested procedure/function
This does not work, a direct capture of nested procedure.
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.
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.Problem is - it isn't right. Why? Because TCapturer can have several Invoke methods. Because closures aren't only about making callbacks with data bound to them. They're about declaring classes without actually declaring classes. Because they're thing from scripted languages, that lack explicit class declaration syntax. And therefore reference to procedure/function should also store pointer to specific method - not pointer to interface only. Therefore it's something like "procedure/function of interface".
Sorry, checked it in Delphi - indeed each reference to procedure/function is separate interface, so no pointer to specific procedure/function is needed.
You think we - or mainly the one who did most of the work regarding function references - didn't do our homework to find out what's going on behind the scenes? ;DMay be my memory fools me or may be it's from older Delphi versions, like 2009. But I always thought, that I investigated it long time ago and that it worked exactly this way.
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 (https://gitlab.com/groups/freepascal.org/fpc/-/issues).
You think we - or mainly the one who did most of the work regarding function references - didn't do our homework to find out what's going on behind the scenes? ;DMay be my memory fools me or may be it's from older Delphi versions, like 2009. But I always thought, that I investigated it long time ago and that it worked exactly this way.
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 (https://gitlab.com/groups/freepascal.org/fpc/-/issues).
Done. See https://gitlab.com/freepascal.org/fpc/source/-/issues/39926