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] Sorting a Stringlist on ValueFromIndex
On Tue, 15 Feb 2022, James Richters wrote: Thanks for the elegant solution Michael, but I'm having some issues implementing it. I'm getting: pastep.pas(28651,10) Warning: Function result does not seem to be set 28650 // Custom compare function 28651 function CompareValues(List: TStringList; Index1, Index2: Integer): Integer; 28652 28653 begin 28654 Result:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) 28655 end; pastep.pas(28797,65) Error: Incompatible type for arg no. 1: Got "Pointer", expected "" 28797 AllLogLastRunStringList.CustomSort(@CompareValues); The unit I'm putting this in has: Unit PAStep; {$Mode TP}{$I-} Ehmmm.. TStringList is not supposed to be used in mode TP, and Result likewise should not be available IIRC... {$modeswitch exceptions} {$R+} I can fix the first error with: 28654 CompareValues:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) {$Mode TP} doesn't like using 'result' But I have no idea how I could fix the second error. Any ideas? Try to remove the @ Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Sorting a Stringlist on ValueFromIndex
Thanks for the elegant solution Michael, but I'm having some issues implementing it. I'm getting: pastep.pas(28651,10) Warning: Function result does not seem to be set 28650 // Custom compare function 28651 function CompareValues(List: TStringList; Index1, Index2: Integer): Integer; 28652 28653 begin 28654 Result:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) 28655 end; pastep.pas(28797,65) Error: Incompatible type for arg no. 1: Got "Pointer", expected "" 28797 AllLogLastRunStringList.CustomSort(@CompareValues); The unit I'm putting this in has: Unit PAStep; {$Mode TP}{$I-} {$modeswitch exceptions} {$R+} I can fix the first error with: 28654 CompareValues:=CompareText(List.ValueFromIndex[Index1],List.ValueFromIndex[Index2]) {$Mode TP} doesn't like using 'result' But I have no idea how I could fix the second error. Any ideas? James ___ 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