Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
On Mon, May 30, 2022 at 7:25 AM Sven Barth via fpc-pascal wrote: > === code begin === > > Sort(lamba (left, right) as > if left < right then -1 > else if left > right then 1 > else 0); > This doesn't look like Pascal at all. I definitively hope this is not the future of our beautiful language. -- Bart ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Am 28.05.2022 um 14:04 schrieb Benito van der Zander via fpc-pascal: Hi, Sort((left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); One could introduce the @ operator to get a reference to a block of code. Sort( @(left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); The sequence "@(identifier" is already a valid sequence (because "@(SomeVar)" is valid) and I'm definitely and absolutely against introducing another ambigous syntax as I already have enough headaches with Delphi's generic syntax. The "result" variable is also ugly. You could make "if" an expression: Sort( @(left, right) begin result := if left < right then -1 else if left > right then 1 else 0; end); Allowing if (and case) to be an expression, too, is something I'm still toying with independantly of this... Then the begin end could be removed too. Make @:= an operator to turn an expression to a function Sort( @(left, right) := if left < right then -1 else if left > right then 1 else 0; ); I personally would have a bit more verbose syntax though it would have the same problem regarding type inference which would be an absolute PITA to implement (not to mention the opposition from the other core devs): === code begin === Sort(lamba (left, right) as if left < right then -1 else if left > right then 1 else 0); === code end === Regards, Sven___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
This is horrendous code, especially the last example. Looks like PHP or JavaScript, which I hate because their code is hard to read. I'm using pascal because I like its clean and easy-to-read syntax. "-1" is a statement that should give a compiler error. "Result" and "Exit(x)" are established constructs and I don't see any need for changing, or even worse: omitting, them. What should the data type of "left, right" be? What should "@" mean? - Original Message - From: Benito van der Zander via fpc-pascal To: fpc-pascal@lists.freepascal.org Sent: Saturday, May 28, 2022, 14:04:46 Subject: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions Hi, > Sort((left, right) begin > if left < right then >result := -1 > else if left > right then >result := 1 > else >result := 0; >end); One could introduce the @ operator to get a reference to a block of code. Sort( @(left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); The "result" variable is also ugly. You could make "if" an expression: Sort( @(left, right) begin result := if left < right then -1 else if left > right then 1 else 0; end); Then the begin end could be removed too. Make @:= an operator to turn an expression to a function Sort( @(left, right) := if left < right then -1 else if left > right then 1 else 0; ); Benito ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
> On May 27, 2022, at 6:31 PM, Marco van de Voort via fpc-pascal > wrote: > > Ditto! https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/39774 > > This ticket also contains an experimental patch for anonymous method queue > and synchronize. (required to reproduce) Yeah code tools is basically broken right now. I don’t think I can even use it right now from my language server because I get the error: invalid mode switch “functionreferences”. Hopefully this can be fixed soon. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
> On May 28, 2022, at 7:04 PM, Benito van der Zander via fpc-pascal > wrote: > > The "result" variable is also ugly. You could make "if" an expression: > > Sort( @(left, right) begin > result := > if left < right then -1 > else if left > right then 1 > else 0; > end); Swift, C# and JavaScript etc… allow you to omit the return statement if the function body is a single expression. I don’t think any languages I’m aware of break the rules of expression though like this is proposing but you could use exit() and it would look a little better. > > > > Then the begin end could be removed too. Make @:= an operator to turn an > expression to a function > > Sort( @(left, right) := >if left < right then -1 >else if left > right then 1 >else 0; > ); I don’t think you need the @ operator here since the ():= is enough to denote a function. This is like the “arrow” syntax in JavaScript and it makes sense to me. It’s a good idea I think. Come to think of it is FPC going to support capture lists? Right now the entire scope is captured but this is not always ideal. Right now there’s no syntax currently available that would support 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] Feature Announcement: Function References and Anonymous Functions
> On May 28, 2022, at 6:39 PM, Michael Van Canneyt via fpc-pascal > wrote: > > And I'm sure it finds these very understandable (live examples): > > [s: string]: ((s: string, cb: (done: any) => void) => void) & ((cb: (done: > any) => void) => void) & {only: any, skip: any}; > load: (url: string, onLoad: (object3D: THREE.Object3D) => void, onProgress?: > (progress: ProgressEvent) => void, onError?: (event: ErrorEvent) => void) => > void; > function comp(c: (c: C) => D, b: (b: B) => C, a: (a: A) => B): > (a: A) => D; > function comp(d: (d: D) => E, c: (c: C) => D, b: (b: B) => C, > a: (a: A) => B): (a: A) => E; > singleton = _.memoize((classInstance: new () => T) => new classInstance()); > function cacheGetter(judgeFunc: () => boolean, returnCacheValueFunc: () => > any, setCacheFunc: (returnVal: any) => void): (target: any, name: any, > descriptor: any) => any; > Yes I see your point here but this can happen to any language with closures and is something FPC needs to reckon with now. Having verbose function declarations could make these kind of nested closures even worse than this. I’m not up to date on how languages like JavaScript are dealing with this problem in their inherently concurrent code but I think they’re moving away from callbacks and closures. See http://callbackhell.com. My point has to do with the best case scenario where adding a function which mean the user needs to scroll up dozens of lines to see what the function does even though it may be only a single expression. This is very common for filter, map etc… container functions. Adding in a fat function declaration doesn’t help the programmer since they already know what the TList.Filter function does and the extra lines make it hard to see what the actual code does. For example you want to filter out items from a list with a value of less than 10. The function is only a single expression so wrapping it up in a 3 extra lines of code is just obscuring the code in my opinion. Swift even has a convention for if the last parameter is a function you can call it with something like this: list.Filter begin result := $0 < 10; end; I really don’t see how the extra "function (item: integer): boolean” makes that easier to read or adds more information. Maybe if you started doing stupid nesting things it will make a difference? list.Filter begin result := $0.PeformCheck begin result := $0 < 10; end; end; list.Filter(function (item: integer): boolean begin result := item.PeformCheck(function: boolean begin result := self < 10; end); end); They both look not great to me but I think this is more with the nesting aspect than the function declaration. What about plain procedures with no parameters? timer.Finished(procedure begin DoTheNextThing; end); Or this: timer.Finished(procedure begin DoTheNextThing end); I’m just not seeing how it helps to write in the procedure keyword in these cases. Anyways, it’s too early to know how this is going to work and I don’t do much concurrent code in Pascal so I likely won’t ever have a chance to write deeply nested functions but lets see what other people end of doing and how it looks. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Hi, Sort((left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); One could introduce the @ operator to get a reference to a block of code. Sort( @(left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); The "result" variable is also ugly. You could make "if" an expression: Sort( @(left, right) begin result := if left < right then -1 else if left > right then 1 else 0; end); Then the begin end could be removed too. Make @:= an operator to turn an expression to a function Sort( @(left, right) := if left < right then -1 else if left > right then 1 else 0; ); Benito On 28.05.22 08:47, Hairy Pixels via fpc-pascal wrote: I’ve had some time to play with this now and my first piece of feedback is that given my experience with other languages, the most common usage of closures is by passing them as arguments to functions. Compared to the other languages I’m using now I’d say that we should be inferring more of the context of the receiving function type and not requiring the programmer to type out the full function header as in the example below (especially in the case there are no local variables declared). Sort(function(left, right: Double): integer begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); It’s hard to say what the best policy is for Pascal but some combination of the function/procedure keyword, parameter type names and return type could be omitted or shortened in various ways. Given we know the function type from the parameter list we could infer most of the information and provide a more limited set of syntax, for example like this (Swift like): Sort((left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); There is even the most limited shorthand (from Swift again) which uses token to represent the arguments as they are ordered. Sort(begin if $0 < right then result := -1 else if $0 > $1 then result := 1 else result := 0; end); Regards, Ryan Joseph ___ 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] Feature Announcement: Function References and Anonymous Functions
On Sat, 28 May 2022, Hairy Pixels via fpc-pascal wrote: On May 28, 2022, at 2:06 PM, Michael Van Canneyt via fpc-pascal wrote: Ah... The desire to make a programming language terse and unreadable as a consequence. If you want that, use C#, Javascript or one of the ubiquitous languages for bracket fetishists. Scala & Rust top the bill in terms of unreadability. So no, that's a "No pasarán". Well that’s been my experience using both Swift and C# frequently over the last couple years that you don’t actually need to see the full function declaration in most instances because it’s inferred from the context. I'm happy for the computer that it can infer things from the context in milliseconds. Really, I stand in awe... And I'm sure it finds these very understandable (live examples): [s: string]: ((s: string, cb: (done: any) => void) => void) & ((cb: (done: any) => void) => void) & {only: any, skip: any}; load: (url: string, onLoad: (object3D: THREE.Object3D) => void, onProgress?: (progress: ProgressEvent) => void, onError?: (event: ErrorEvent) => void) => void; function comp(c: (c: C) => D, b: (b: B) => C, a: (a: A) => B): (a: A) => D; function comp(d: (d: D) => E, c: (c: C) => D, b: (b: B) => C, a: (a: A) => B): (a: A) => E; singleton = _.memoize((classInstance: new () => T) => new classInstance()); function cacheGetter(judgeFunc: () => boolean, returnCacheValueFunc: () => any, setCacheFunc: (returnVal: any) => void): (target: any, name: any, descriptor: any) => any; However, I as a human have a brain that works at lower clock cycles, but even so I like to see at a glance what is intended without having to think too long on 'what on earth could missus X have meant here ?'. That means providing a little more context/structure, and keeping the door firmly closed for syntax that allows absurd monstrosities as the things above. (and preferably lock it, take out the key and throw it away while we're at it) This is - incidentally - also why I think pascal should never allow type definitions in function arguments. For similar reasons I deplore the popularity of YAML or markdown, which all too often provide too little structure to grasp what is meant. By contrast XML is too much cruft, but e.g. JSON strikes a good balance. Programming languages are meant for humans, not for computers. If it were up to the computer, we'd probably simply write out programs as sequences of 0-s and 1-s. Guaranteed to be the shortest notation, but good luck trying to make sense of that as a human. I suspect punched cards are a thing of the past just for this reason. The downside is that every human has his likes and dislikes. But, if you actually prefer the above syntax to the more verbose pascal, you're in luck: There are many languages that will allow you to knock yourself out =-) Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
> On May 28, 2022, at 2:06 PM, Michael Van Canneyt via fpc-pascal > wrote: > > Ah... > > The desire to make a programming language terse and unreadable as a > consequence. > If you want that, use C#, Javascript or one of the ubiquitous languages for > bracket fetishists. > Scala & Rust top the bill in terms of unreadability. > > So no, that's a "No pasarán". Well that’s been my experience using both Swift and C# frequently over the last couple years that you don’t actually need to see the full function declaration in most instances because it’s inferred from the context. I’m actually finding it harder to read the Pascal syntax because there’s so much slammed in the function call. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
On Sat, 28 May 2022, Hairy Pixels via fpc-pascal wrote: I’ve had some time to play with this now and my first piece of feedback is that given my experience with other languages, the most common usage of closures is by passing them as arguments to functions. Compared to the other languages I’m using now I’d say that we should be inferring more of the context of the receiving function type and not requiring the programmer to type out the full function header as in the example below (especially in the case there are no local variables declared). Sort(function(left, right: Double): integer begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); It’s hard to say what the best policy is for Pascal but some combination of the function/procedure keyword, parameter type names and return type could be omitted or shortened in various ways. Ah... The desire to make a programming language terse and unreadable as a consequence. If you want that, use C#, Javascript or one of the ubiquitous languages for bracket fetishists. Scala & Rust top the bill in terms of unreadability. So no, that's a "No pasarán". Pascal is verbose and explicit, it enhances readability & clarity of code. Any proposal to undo that, is not acceptable. If it was not for Delphi compatibility, I would kick out anonymous functions outright. Local functions can fulfill the need for closures perfectly, which results in more readable code as far as I am concerned. Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
I’ve had some time to play with this now and my first piece of feedback is that given my experience with other languages, the most common usage of closures is by passing them as arguments to functions. Compared to the other languages I’m using now I’d say that we should be inferring more of the context of the receiving function type and not requiring the programmer to type out the full function header as in the example below (especially in the case there are no local variables declared). Sort(function(left, right: Double): integer begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); It’s hard to say what the best policy is for Pascal but some combination of the function/procedure keyword, parameter type names and return type could be omitted or shortened in various ways. Given we know the function type from the parameter list we could infer most of the information and provide a more limited set of syntax, for example like this (Swift like): Sort((left, right) begin if left < right then result := -1 else if left > right then result := 1 else result := 0; end); There is even the most limited shorthand (from Swift again) which uses token to represent the arguments as they are ordered. Sort(begin if $0 < right then result := -1 else if $0 > $1 then result := 1 else result := 0; 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] Feature Announcement: Function References and Anonymous Functions
On 27.05.2022 00:23, Zoë Peterson via fpc-pascal wrote: Sven, I'm absolutely thrilled to see this finally merged. I sincerely appreciate all of the work that you and Blaise put into it over such a long time. I can't wait to see what the community is able to do with it. Thank you, and thank you to the entire Free Pascal team for everything you've all built. Sven & Blaise, I thank you for this enormous achievement as well! Ondrej ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
On 27-5-2022 14:12, Sven Barth via fpc-pascal wrote: You couldn't have written a test that's independent of TThread? 梁 When I saw no reactions on core this morning, I dumped everything I had to the respective issue trackers. I'm not sure if I can get all of this reproduced on my private laptop when I'm away this weekend. If it is about the overload case: well, you said it would be easy because objfpc already did it right :-) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Marco van de Voort via fpc-pascal schrieb am Fr., 27. Mai 2022, 13:31: > > On 27-5-2022 00:46, Mattias Gaertner via fpc-pascal wrote: > > > >> As these two features are rather complicated there might still be a > >> huge bundle of bugs lurking around so I ask you to test them to year > >> heart's content and report found bugs > > First! > > Ditto! https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/39774 > > This ticket also contains an experimental patch for anonymous method > queue and synchronize. (required to reproduce) > You couldn't have written a test that's independent of TThread? 梁 Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
On 27-5-2022 00:46, Mattias Gaertner via fpc-pascal wrote: As these two features are rather complicated there might still be a huge bundle of bugs lurking around so I ask you to test them to year heart's content and report found bugs First! Ditto! https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/39774 This ticket also contains an experimental patch for anonymous method queue and synchronize. (required to reproduce) ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Am 27.05.2022 um 00:46 schrieb Mattias Gaertner via fpc-pascal: On Thu, 26 May 2022 21:47:06 +0200 Sven Barth via fpc-pascal wrote: As these two features are rather complicated there might still be a huge bundle of bugs lurking around so I ask you to test them to year heart's content and report found bugs First! At least it was an easy one for starters ^^' Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
> On May 27, 2022, at 2:47 AM, Sven Barth via fpc-pascal > wrote: > > Further RTL enhancements like the declaration of TProc<> or the addition of a > TThread.Queue() that takes a function reference will come in the near future > now that the basics on the compiler side are done. Maybe we can now also > tackle ports of libraries like Spring4D and OmniThreadLibrary. There's also > the idea to introduce a syntax to control whether symbols are captured > by-reference (as currently) or by-value. > > Enjoy! Huge news, I’m so excited about this. Thank you both. As discussed over the last years, now that we’ve implemented the anonymous functions part can we consider an optimization for closures that don’t leave the current scope? I explored the possibility of using the existing nested function feature and I think that would work great with the anonymous functions syntax. The open questions are: 1) How does the compiler know the closure will not leave the scope? 2) The actual implementation, leverage the nested functions which are stacked based objects or change the closure capture object to be a record instead of an interface (much more work I believe). Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Great!!! Thank you very very much :))) - Original Message - From: Sven Barth via fpc-pascal To: fpc-annou...@lists.freepascal.org Sent: Thursday, May 26, 2022, 21:47:06 Subject: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions Dear Free Pascal Community, The Free Pascal Developer team is pleased to finally announce the addition of a long awaited feature, though to be precise it's two different, but very much related features: Function References and Anonymous Functions. These two features can be used independantly of each other, but their greatest power they unfold when used together. These features are based on the work by Blaise.ru, so thank you very much and I hope you're doing well considering the current situation. In the following we'll highlight both features separately and then we'll take a look at using them together. = Function References = Function References (also applicable names are Procedure References and Routine References, in the following only Function References will be used) are types that can take a function (or procedure or routine), method, function variable (or procedure variable or routine variable), method variable, nested function (or nested procedure or nested routine) or an anonymous function (or anonymous procedure or anonymous routine) as a value. The function reference can then be used to call the provided function just like other similar routine pointer types. In contrast to these other types nearly all function-like constructs can be assigned to it (the only exception are nested function variables (or nested procedure variables or nested routine variables), more about that later on) and then used or stored. Function references are enabled with the modeswitch FUNCTIONREFERENCES (the following examples will assume that this modeswitch is provided). A function reference is declared as follows: REFERENCE TO FUNCTION|PROCEDURE [(argumentlist)][: resulttype;] [directives;] Examples: === code begin === type TProcLongInt = reference to procedure(aArg: LongInt); stdcall; TFuncTObject = reference to function(aArg: TObject): TObject; === code end === Like other function pointer types function references can also be declared as generic: === code begin === type generic TGenericProc = reference to procedure(aArg: T); === code end === As you can see, once function references are enabled you can't use the identifier "REFERENCE" as part of an alias declaration without using "&": === code begin === type someref = reference; // will fail someref = // correct fix var somevar: reference; // will fail somevar: // correct fix === code end === A function reference variable can then be called like any other function pointer type: === code begin === var p: TProcLongInt; begin p := @SomeLongIntProc; p(42); end. === code end === If a function reference has no parameters then you need to use "()" nevertheless in the FPC/ObjFPC modes like for other function pointer types: === code begin === type TProc = reference to procedure; var p: TProc; begin p := @SomeProcedure; p(); // required p; // this can be used e.g. in mode Delphi end. === code end === Like other function pointer types they can also be declared anonymously as part of a variable, field declaration (but not as part of a paramater declaration): === code begin === var f: reference to function: LongInt; type TTest = class f: reference to procedure; end; === code end === They get their great power from a point that is for once *not* considered an implementation detail: function references are in fact internally declared as reference counted interfaces with a single Invoke() method of the provided signature. So the above examples are in fact declared like this: === code begin === type TProcLongInt = interface(IInterface) procedure Invoke(aArg: LongInt); stdcall; overload; end; TFuncTObject = interface(IInterface) procedure Invoke(aArg: TObject): TObject; overload; end; generic TGenericProc = interface(IInterface) procedure Invoke(aArg: T); overload; end; === code end === This has a few implications: - in the RTTI this will appear like a normal interface - it reacts to the $M directive like a normal interface - it is a managed type - it has *no* valid GUID - it can be implemented by a class - it can be inherited from Especially the last two points are important. That the interface can be implemented means that much more functionality and state can be added to a function reference: === code begin === type TFunc = reference to function: LongInt; TSomeImpl = class(TInterfacedObject, TFunc) f: LongInt; function Invoke: LongInt; end; function TSomeImpl.Invoke: LongInt; begin Result := f; end; var t: TSomeImpl; f: TFunc; begin t := TSomeImpl.Create; f := t; Writeln(
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
On Thu, 26 May 2022 21:47:06 +0200 Sven Barth via fpc-pascal wrote: >[...] > The Free Pascal Developer team is pleased to finally announce the > addition of a long awaited feature, though to be precise it's two > different, but very much related features: Function References and > Anonymous Functions. \O/ >[...] > As these two features are rather complicated there might still be a > huge bundle of bugs lurking around so I ask you to test them to year > heart's content and report found bugs First! >[...] Mattias ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Sven, I'm absolutely thrilled to see this finally merged. I sincerely appreciate all of the work that you and Blaise put into it over such a long time. I can't wait to see what the community is able to do with it. Thank you, and thank you to the entire Free Pascal team for everything you've all built. -- Zoë Peterson Scooter Software ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Hello ! Nice job, kudos both for Blaise and Sven, and special thanks to Zoë Peterson for donating the code to FPC, as Scooter Software sponsored the initial work by Blaise. I'm glad to see that the FPC implementation makes the distinction between function references and anonymous functions very explicitly :-) Michael. On Thu, 26 May 2022, Sven Barth via fpc-pascal wrote: Dear Free Pascal Community, The Free Pascal Developer team is pleased to finally announce the addition of a long awaited feature, though to be precise it's two different, but very much related features: Function References and Anonymous Functions. These two features can be used independantly of each other, but their greatest power they unfold when used together. These features are based on the work by Blaise.ru, so thank you very much and I hope you're doing well considering the current situation. In the following we'll highlight both features separately and then we'll take a look at using them together. = Function References = Function References (also applicable names are Procedure References and Routine References, in the following only Function References will be used) are types that can take a function (or procedure or routine), method, function variable (or procedure variable or routine variable), method variable, nested function (or nested procedure or nested routine) or an anonymous function (or anonymous procedure or anonymous routine) as a value. The function reference can then be used to call the provided function just like other similar routine pointer types. In contrast to these other types nearly all function-like constructs can be assigned to it (the only exception are nested function variables (or nested procedure variables or nested routine variables), more about that later on) and then used or stored. Function references are enabled with the modeswitch FUNCTIONREFERENCES (the following examples will assume that this modeswitch is provided). A function reference is declared as follows: REFERENCE TO FUNCTION|PROCEDURE [(argumentlist)][: resulttype;] [directives;] Examples: === code begin === type TProcLongInt = reference to procedure(aArg: LongInt); stdcall; TFuncTObject = reference to function(aArg: TObject): TObject; === code end === Like other function pointer types function references can also be declared as generic: === code begin === type generic TGenericProc = reference to procedure(aArg: T); === code end === As you can see, once function references are enabled you can't use the identifier "REFERENCE" as part of an alias declaration without using "&": === code begin === type someref = reference; // will fail someref = // correct fix var somevar: reference; // will fail somevar: // correct fix === code end === A function reference variable can then be called like any other function pointer type: === code begin === var p: TProcLongInt; begin p := @SomeLongIntProc; p(42); end. === code end === If a function reference has no parameters then you need to use "()" nevertheless in the FPC/ObjFPC modes like for other function pointer types: === code begin === type TProc = reference to procedure; var p: TProc; begin p := @SomeProcedure; p(); // required p; // this can be used e.g. in mode Delphi end. === code end === Like other function pointer types they can also be declared anonymously as part of a variable, field declaration (but not as part of a paramater declaration): === code begin === var f: reference to function: LongInt; type TTest = class f: reference to procedure; end; === code end === They get their great power from a point that is for once *not* considered an implementation detail: function references are in fact internally declared as reference counted interfaces with a single Invoke() method of the provided signature. So the above examples are in fact declared like this: === code begin === type TProcLongInt = interface(IInterface) procedure Invoke(aArg: LongInt); stdcall; overload; end; TFuncTObject = interface(IInterface) procedure Invoke(aArg: TObject): TObject; overload; end; generic TGenericProc = interface(IInterface) procedure Invoke(aArg: T); overload; end; === code end === This has a few implications: - in the RTTI this will appear like a normal interface - it reacts to the $M directive like a normal interface - it is a managed type - it has *no* valid GUID - it can be implemented by a class - it can be inherited from Especially the last two points are important. That the interface can be implemented means that much more functionality and state can be added to a function reference: === code begin === type TFunc = reference to function: LongInt; TSomeImpl = class(TInterfacedObject, TFunc) f: LongInt; function Invoke: LongInt; end; function TSomeImpl.Invoke: LongInt; begin Result := f; end; var t: TSomeImpl; f: TFunc;
[fpc-pascal] Feature Announcement: Function References and Anonymous Functions
Dear Free Pascal Community, The Free Pascal Developer team is pleased to finally announce the addition of a long awaited feature, though to be precise it's two different, but very much related features: Function References and Anonymous Functions. These two features can be used independantly of each other, but their greatest power they unfold when used together. These features are based on the work by Blaise.ru, so thank you very much and I hope you're doing well considering the current situation. In the following we'll highlight both features separately and then we'll take a look at using them together. = Function References = Function References (also applicable names are Procedure References and Routine References, in the following only Function References will be used) are types that can take a function (or procedure or routine), method, function variable (or procedure variable or routine variable), method variable, nested function (or nested procedure or nested routine) or an anonymous function (or anonymous procedure or anonymous routine) as a value. The function reference can then be used to call the provided function just like other similar routine pointer types. In contrast to these other types nearly all function-like constructs can be assigned to it (the only exception are nested function variables (or nested procedure variables or nested routine variables), more about that later on) and then used or stored. Function references are enabled with the modeswitch FUNCTIONREFERENCES (the following examples will assume that this modeswitch is provided). A function reference is declared as follows: REFERENCE TO FUNCTION|PROCEDURE [(argumentlist)][: resulttype;] [directives;] Examples: === code begin === type TProcLongInt = reference to procedure(aArg: LongInt); stdcall; TFuncTObject = reference to function(aArg: TObject): TObject; === code end === Like other function pointer types function references can also be declared as generic: === code begin === type generic TGenericProc = reference to procedure(aArg: T); === code end === As you can see, once function references are enabled you can't use the identifier "REFERENCE" as part of an alias declaration without using "&": === code begin === type someref = reference; // will fail someref = // correct fix var somevar: reference; // will fail somevar: // correct fix === code end === A function reference variable can then be called like any other function pointer type: === code begin === var p: TProcLongInt; begin p := @SomeLongIntProc; p(42); end. === code end === If a function reference has no parameters then you need to use "()" nevertheless in the FPC/ObjFPC modes like for other function pointer types: === code begin === type TProc = reference to procedure; var p: TProc; begin p := @SomeProcedure; p(); // required p; // this can be used e.g. in mode Delphi end. === code end === Like other function pointer types they can also be declared anonymously as part of a variable, field declaration (but not as part of a paramater declaration): === code begin === var f: reference to function: LongInt; type TTest = class f: reference to procedure; end; === code end === They get their great power from a point that is for once *not* considered an implementation detail: function references are in fact internally declared as reference counted interfaces with a single Invoke() method of the provided signature. So the above examples are in fact declared like this: === code begin === type TProcLongInt = interface(IInterface) procedure Invoke(aArg: LongInt); stdcall; overload; end; TFuncTObject = interface(IInterface) procedure Invoke(aArg: TObject): TObject; overload; end; generic TGenericProc = interface(IInterface) procedure Invoke(aArg: T); overload; end; === code end === This has a few implications: - in the RTTI this will appear like a normal interface - it reacts to the $M directive like a normal interface - it is a managed type - it has *no* valid GUID - it can be implemented by a class - it can be inherited from Especially the last two points are important. That the interface can be implemented means that much more functionality and state can be added to a function reference: === code begin === type TFunc = reference to function: LongInt; TSomeImpl = class(TInterfacedObject, TFunc) f: LongInt; function Invoke: LongInt; end; function TSomeImpl.Invoke: LongInt; begin Result := f; end; var t: TSomeImpl; f: TFunc; begin t := TSomeImpl.Create; f := t; Writeln(f()); // will write 0 t.f := 42; Writeln(f()); // will write 42 f := Nil; // the usual warnings about mixing classes and interface apply! end. === code end === As function references don't have valid GUIDs you can't however use QueryInterface() or the as-operator to retrieve it. Using the low level interface related