Re: [fpc-pascal] Caller agnostic procedure variables
Sven Barth via fpc-pascal wrote: "However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. " "is nested" means that the actual function passed can be either global or local. ISO Pascal style function parameters are implicitely "is nested". The formal function reference for an "is nested" function contains space for both a function address and a context pointer. The context pointer is NIL if the actual function is declared global. For local functions, the context pointer typically contains a dynamic link chain pointer, required to address variables in the actual link frame. For object methods, the context pointer is the SELF pointer. Regards, Adriaan van Os ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Mi., 16. Feb. 2022, 07:59: > > > > On Feb 16, 2022, at 2:46 AM, Sven Barth via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > // nested function/procedure/routine variable > > type > > TFoobarNested = function: LongInt is nested; > > > > var > >f: TFoobarFuncRef; > > begin > > // anonymous function/procedure/routine > > f := function: LongInt > > begin > > end; > > end; > > "However assigning a nested function variable to a function reference is > much harder. > Assigning a function reference to a nested function variable is hard as > well. " > > This means if you expanded your example with: > > var > n: TFoobarNested; > begin > f := n; > > THAT would be hard? I've never passed around nested function vars before > so I don't really know the limitations of this. The important thing is the > primary use case works. > Correct. In addition to that the general assumption for function references is that they can be called even after the function they were assigned to has been left. For a nested function itself this can hold true as well (cause the compiler simply needs to transform the nested function correctly when generating the implementation for the capture object), but for a nested function variable this assumption would be wrong. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Mi., 16. Feb. 2022, 03:14: > > > > On Feb 15, 2022, at 11:09 PM, Sven Barth via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > For a global function the compiler has to generate a wrapper that gets > rid of the Self parameter of the interface. > > > > The compiler generates this interface at compile time right? And then when > the scope of the calling function is entered the interface is allocated? I > know that's how it works for the case when state is captured but I think > you're saying this is happening any time a function reference is assigned > to, even if there is no state captured. Just trying to get an understanding > of the runtime cost to use these. > The compiler is generating the *implementation* of the interface that is the function reference. The capture object with this implementation as a method is then shared by everything that's assigned to a function reference (doesn't need to be the same one). So one instance will be allocated each time the function is entered. This is the general case. For some very specific cases there can be optimizations that can work without allocations, but that's a topic for the future. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 16, 2022, at 12:18 AM, Thomas Kurz via fpc-pascal > wrote: > > What release are anonymous functions planed for? FPC 3.4.0? They aren't even in trunk yet. Could be months or years. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 11:09 PM, Sven Barth via fpc-pascal > wrote: > > For a global function the compiler has to generate a wrapper that gets rid of > the Self parameter of the interface. > The compiler generates this interface at compile time right? And then when the scope of the calling function is entered the interface is allocated? I know that's how it works for the case when state is captured but I think you're saying this is happening any time a function reference is assigned to, even if there is no state captured. Just trying to get an understanding of the runtime cost to use these. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 16, 2022, at 2:46 AM, Sven Barth via fpc-pascal > wrote: > > // nested function/procedure/routine variable > type > TFoobarNested = function: LongInt is nested; > > var >f: TFoobarFuncRef; > begin > // anonymous function/procedure/routine > f := function: LongInt > begin > end; > end; "However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. " This means if you expanded your example with: var n: TFoobarNested; begin f := n; THAT would be hard? I've never passed around nested function vars before so I don't really know the limitations of this. The important thing is the primary use case works. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Am 15.02.2022 um 15:05 schrieb Ryan Joseph via fpc-pascal: On Feb 15, 2022, at 8:26 PM, Sven Barth via fpc-pascal wrote: It's relatively "easy" to implement assigning a nested function to function references. However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. I'm getting lost with the terms now I think. If your function takes a function reference parameter and you assign it a nested function pointer, this is difficult? I believe this was Michaels request in that code snippet. === code excerpt begin === // function/procedure/routine function Foobar: LongInt; forward; // function/procedure/routine variable type TFoobarFunc = function: LongInt; // method TFoo = class function Foobar: LongInt; end; // method variable TFoobarMethod = function: LongInt of object; // function/procedure/routine reference TFoobarFuncRef = reference to function: LongInt; function Foobar: LongInt; // nested function/procedure/routine function FoobarSub: LongInt; begin end; // nested function/procedure/routine variable type TFoobarNested = function: LongInt is nested; var f: TFoobarFuncRef; begin // anonymous function/procedure/routine f := function: LongInt begin end; end; === code excerpt end === Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> The "Reference to procedure" that will be part of anonymous functionswill do > this for you. What release are anonymous functions planed for? FPC 3.4.0? ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Di., 15. Feb. 2022, 15:02: > > > > On Feb 15, 2022, at 8:32 PM, Sven Barth via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > A function reference is simply an interface of which the Invoke method > can be called on the instance instead of manually doing "Foo.Invoke". > > > > The real "magic" is when the compiler generates the *implementation* of > said interface. So in the end what can be assigned to a function reference > depends on the compiler being able to generate suitable implementations. > > So when you assign a global function to a function reference it has to > generate a new function body? I guess that makes sense on how it can > "capture" these different types of functions. > For a global function the compiler has to generate a wrapper that gets rid of the Self parameter of the interface. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Michael Van Canneyt via fpc-pascal schrieb am Di., 15. Feb. 2022, 15:29: > > > On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: > > > > > > >> On Feb 15, 2022, at 8:26 PM, Sven Barth via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > >> > >> It's relatively "easy" to implement assigning a nested function to > function references. However assigning a nested function variable to a > function reference is much harder. > >> Assigning a function reference to a nested function variable is hard as > well. > >> > > > > I'm getting lost with the terms now I think. > > If your function takes a function reference parameter and you assign it > a nested function pointer, > > this is difficult? I believe this was Michaels request in that code > snippet. > > Sven will need to confirm, but as I understand it: > > Procedure DoDemo(aTest : TProc); > > Procedure MyTest; > >Procedure DoSub; >begin >end; > > begin >DoDemo(DoSub) > end; > > is easy. > > but > > Procedure DoDemo(aTest : TProc); > > Procedure MyTest; > > Var >ASub : procedure is nested; > > begin >aSub:=SomeFunctionThatReturnsANestedProc; >DoDemo(aSub); > end; > > is difficult. > Correct (yes, I saw your addendum). Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
On Tue, 15 Feb 2022, Michael Van Canneyt via fpc-pascal wrote: On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: On Feb 15, 2022, at 8:26 PM, Sven Barth via fpc-pascal wrote: It's relatively "easy" to implement assigning a nested function to function references. However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. I'm getting lost with the terms now I think. If your function takes a function reference parameter and you assign it a nested function pointer, this is difficult? I believe this was Michaels request in that code snippet. Sven will need to confirm, but as I understand it: Procedure DoDemo(aTest : TProc); For clarity, this should be something like: Procedure DoDemo(aTest : TProc); begin // Do stuff aTest; end; So the below procedures are not local to DoDemo... Michael. Procedure MyTest; Procedure DoSub; begin end; begin DoDemo(DoSub) end; is easy. but Procedure DoDemo(aTest : TProc); Procedure MyTest; Var ASub : procedure is nested; begin aSub:=SomeFunctionThatReturnsANestedProc; DoDemo(aSub); end; is difficult. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: On Feb 15, 2022, at 8:26 PM, Sven Barth via fpc-pascal wrote: It's relatively "easy" to implement assigning a nested function to function references. However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. I'm getting lost with the terms now I think. If your function takes a function reference parameter and you assign it a nested function pointer, this is difficult? I believe this was Michaels request in that code snippet. Sven will need to confirm, but as I understand it: Procedure DoDemo(aTest : TProc); Procedure MyTest; Procedure DoSub; begin end; begin DoDemo(DoSub) end; is easy. but Procedure DoDemo(aTest : TProc); Procedure MyTest; Var ASub : procedure is nested; begin aSub:=SomeFunctionThatReturnsANestedProc; DoDemo(aSub); end; is difficult. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 8:26 PM, Sven Barth via fpc-pascal > wrote: > > It's relatively "easy" to implement assigning a nested function to function > references. However assigning a nested function variable to a function > reference is much harder. > Assigning a function reference to a nested function variable is hard as well. > I'm getting lost with the terms now I think. If your function takes a function reference parameter and you assign it a nested function pointer, this is difficult? I believe this was Michaels request in that code snippet. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 8:32 PM, Sven Barth via fpc-pascal > wrote: > > A function reference is simply an interface of which the Invoke method can be > called on the instance instead of manually doing "Foo.Invoke". > > The real "magic" is when the compiler generates the *implementation* of said > interface. So in the end what can be assigned to a function reference depends > on the compiler being able to generate suitable implementations. So when you assign a global function to a function reference it has to generate a new function body? I guess that makes sense on how it can "capture" these different types of functions. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Di., 15. Feb. 2022, 13:14: > > > > On Feb 15, 2022, at 5:15 PM, Sven Barth > wrote: > > > > It contains a capture object that backs the method. > > If nothing is captured and the right hand side is a direct function or > method pointer then the compiler could in principle create something that > is essentially static to avoid allocations, but that would be a future > optimization. > > > > So if we do this there is nothing being captured right? In that case we > get an interface which can call a function pointer? Does the interface then > know about "of object" and "is nested" types at all or does it use a > totally different mechanism to call those? > A function reference is simply an interface of which the Invoke method can be called on the instance instead of manually doing "Foo.Invoke". The real "magic" is when the compiler generates the *implementation* of said interface. So in the end what can be assigned to a function reference depends on the compiler being able to generate suitable implementations. Anonymous functions are a given. Global functions and methods are required to work as well. Nested functions can be made to use as well. Function and method variables can be supported relatively easily as well. Only nested function variables are hard to support. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Di., 15. Feb. 2022, 13:06: > > > > On Feb 15, 2022, at 3:32 PM, Michael Van Canneyt via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > I requested that this: > > > > procedure TMyObject.Demo; > > > > Procedure DoSub; > > begin > >Writeln('Sub'); > > end; > > > > begin > > DoTest(DoSub); > > end; > > So that means "reference to procedure" is not compatible with "is nested"? > It's relatively "easy" to implement assigning a nested function to function references. However assigning a nested function variable to a function reference is much harder. Assigning a function reference to a nested function variable is hard as well. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Di., 15. Feb. 2022, 13:16: > > > > On Feb 15, 2022, at 7:10 PM, Michael Van Canneyt > wrote: > > > > In Delphi it is not. In FPC it should be :-) > > Indeed should be but that's what I'm trying to figure out with how this is > implemented. > > Why wouldn't Delphi be able to do this I wonder. The calling mechanism in > this object is not clear to me so I'll wait for Sven to answer on that. > Delphi doesn't support "is nested", so there is nothing for them to support there. Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 7:10 PM, Michael Van Canneyt > wrote: > > In Delphi it is not. In FPC it should be :-) Indeed should be but that's what I'm trying to figure out with how this is implemented. Why wouldn't Delphi be able to do this I wonder. The calling mechanism in this object is not clear to me so I'll wait for Sven to answer on that. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 5:15 PM, Sven Barth wrote: > > It contains a capture object that backs the method. > If nothing is captured and the right hand side is a direct function or method > pointer then the compiler could in principle create something that is > essentially static to avoid allocations, but that would be a future > optimization. > So if we do this there is nothing being captured right? In that case we get an interface which can call a function pointer? Does the interface then know about "of object" and "is nested" types at all or does it use a totally different mechanism to call those? type TMyAction = reference to procedure; procedure MyAction; begin end; procedure Test; begin DoThis(@MyAction); end; Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: On Feb 15, 2022, at 3:32 PM, Michael Van Canneyt via fpc-pascal wrote: I requested that this: procedure TMyObject.Demo; Procedure DoSub; begin Writeln('Sub'); end; begin DoTest(DoSub); end; So that means "reference to procedure" is not compatible with "is nested"? In Delphi it is not. In FPC it should be :-) Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 3:32 PM, Michael Van Canneyt via fpc-pascal > wrote: > > I requested that this: > > procedure TMyObject.Demo; > > Procedure DoSub; > begin >Writeln('Sub'); > end; > > begin > DoTest(DoSub); > end; So that means "reference to procedure" is not compatible with "is nested"? Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
Ryan Joseph via fpc-pascal schrieb am Di., 15. Feb. 2022, 08:34: > > > > On Feb 15, 2022, at 2:09 PM, Michael Van Canneyt via fpc-pascal < > fpc-pascal@lists.freepascal.org> wrote: > > > > I've answered this question before: > > > > The "Reference to procedure" that will be part of anonymous > functionswill do this for you. > > I'm sorry I forgot! This thing keeps coming up for me and driving me nuts > but I knew I asked in passing before. > > So "reference to procedure" are going to be the new standard? To extend my > example it would look like this? I please remind me, is there a closure > involved which is capturing state and adding overhead? > It contains a capture object that backs the method. If nothing is captured and the right hand side is a direct function or method pointer then the compiler could in principle create something that is essentially static to avoid allocations, but that would be a future optimization. > I'm curious what this type actually is also, maybe a dispatch table which > wraps the existing types or is it something totally new? > A function reference is essentially a reference counted interface with a single method named "Invoke". And before you ask: no, we're not going to add yet another type that combines all four when a function reference does that perfectly well already even if it might be more expensive (note: it's not the call that is that much more expensive, but the creation). Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: On Feb 15, 2022, at 2:09 PM, Michael Van Canneyt via fpc-pascal wrote: I've answered this question before: The "Reference to procedure" that will be part of anonymous functionswill do this for you. I'm sorry I forgot! This thing keeps coming up for me and driving me nuts but I knew I asked in passing before. So "reference to procedure" are going to be the new standard? I don't know what you mean by 'new standard', but a new type, yes. We're not going to change all procedural types to this new type, if that's what you have in mind. To extend my example it would look like this? I please remind me, is there a closure involved which is capturing state and adding overhead? There is not necessarily a closure; only if you use an anonymous function. I'm curious what this type actually is also, maybe a dispatch table which wraps the existing types or is it something totally new? I will leave it to the compiler people to answer this, because I don't know the low-level details. type TMyAction = reference to procedure; procedure DoThis(action: TMyAction); begin action(); end; Yes. The following compiles and runs in delphi: program procdemo; {$APPTYPE CONSOLE} {$R *.res} Type TProc = reference to procedure; TMyObject = Class Procedure DoA; Procedure DoTest(aTest : TProc); Procedure Demo; End; Procedure DoPlain; begin Writeln('Plain'); end; { TMyObject } procedure TMyObject.Demo; begin DoTest(DoA); DoTest(DoPlain); DoTest(Procedure begin Writeln('anonymous'); end); end; procedure TMyObject.DoA; begin Writeln(ClassName,': A'); end; procedure TMyObject.DoTest(aTest: TProc); begin aTest; end; begin With TMyObject.Create do try Demo; finally Free; end; end. I requested that this: procedure TMyObject.Demo; Procedure DoSub; begin Writeln('Sub'); end; begin DoTest(DoSub); end; would also work. It does not work in Delphi, but Pas2js already supports that. I think it results in more readable code - the whole anonymous stuff doesn't really work for me... Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
> On Feb 15, 2022, at 2:09 PM, Michael Van Canneyt via fpc-pascal > wrote: > > I've answered this question before: > > The "Reference to procedure" that will be part of anonymous functionswill do > this for you. I'm sorry I forgot! This thing keeps coming up for me and driving me nuts but I knew I asked in passing before. So "reference to procedure" are going to be the new standard? To extend my example it would look like this? I please remind me, is there a closure involved which is capturing state and adding overhead? I'm curious what this type actually is also, maybe a dispatch table which wraps the existing types or is it something totally new? type TMyAction = reference to procedure; procedure DoThis(action: TMyAction); begin action(); end; Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Caller agnostic procedure variables
On Tue, 15 Feb 2022, Ryan Joseph via fpc-pascal wrote: This has been a constant problem for me with FPC and wanted to make a formal post with code examples since I've only mentioned it in passing before. How can it be achieved to have a caller agnostic procedure variables? I've tried making some big crazy dispatch record that uses generics but because generics don't support variable templates (like some languages have TClass) it was limited and clunky to use. The problem is that from the perspective of the receiver it shouldn't really care what the caller has provided except for that there is a procedure that needs to be called. For example if there is a "sort" function that takes a procedure variable it shouldn't care if the procedure is a global function, a method or a nested function (and eventually a closure). It feels like the compiler needs a new type which encapsulates these different types but I'm not sure how this all works internally. Any thoughts on this? I've answered this question before: The "Reference to procedure" that will be part of anonymous functionswill do this for you. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal