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
> 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: 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
[fpc-pascal] Compiler flag define or $IFOPT for optimizations
Hallo, I want to show how my program was compiled. Now I have string like "FPC3.2.2 i386-Linux R+C+" from compiler := 'FPC' + {$INCLUDE %FPCVERSION%} + ' ' + {$INCLUDE %FPCTargetCPU%}+'-'+{$INCLUDE %FPCTargetOS%}+ ' ' + {$IfOpt R+}+'R+'{$endif} {$IfOpt S+}+'S+'{$endif} {$IfOpt O+}+'O+'{$endif} {$IfOpt Q+}+'Q+'{$endif} {$IfOpt M+}+'M+'{$endif} {$IfOpt C+}+'C+'{$endif}; But the optimization level (-O2 or -O1 ...) is missing. Is there an IFOPT for that? Or a define with all the arguments Bye, 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
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] Compiler flag define or $IFOPT for optimizations
On 2022-05-28 13:44, Benito van der Zander via fpc-pascal wrote: Hi, I want to show how my program was compiled. Now I have string like "FPC3.2.2 i386-Linux R+C+" from compiler := 'FPC' + {$INCLUDE %FPCVERSION%} + ' ' + {$INCLUDE %FPCTargetCPU%}+'-'+{$INCLUDE %FPCTargetOS%}+ ' ' + {$IfOpt R+}+'R+'{$endif} {$IfOpt S+}+'S+'{$endif} {$IfOpt O+}+'O+'{$endif} {$IfOpt Q+}+'Q+'{$endif} {$IfOpt M+}+'M+'{$endif} {$IfOpt C+}+'C+'{$endif}; But the optimization level (-O2 or -O1 ...) is missing. Is there an IFOPT for that? Or a define with all the arguments I don't think that there's such an option at the moment. However, you can possibly solve it by always taking the options from an environment variable to the command line and then including contents of this command line to your sources. I don't think that it makes much sense for the compiler to provide such an option, because unlike the compiler version, different options (including the optimization level) may be used for compilation of different units and there's no such a thing as a general optimization level valid for the complete compiled program from the compiler point of view. You can introduce something like that yourself by always building all your sources from scratch, but then the solution outlined above should work for you. Tomas ___ 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
> 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 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
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
[fpc-pascal] "Is nested" vs "of object" compatibility with global functions
I’ve been testing out all the different function pointer types in FPC to test their compatibility with each other and I noticed that “is nested” can accept a global function declaration but “of object” can not. What is the reason for this exactly? I wouldn’t expect nested function types to accept global functions but since they do I wonder why “of object” is different. I think they both have a hidden first parameter (like self) and nested types simply ignore this for global functions so I would think objects types could do the same. Regards, Ryan Joseph ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] "Is nested" vs "of object" compatibility with global functions
On Sun, 29 May 2022, Hairy Pixels via fpc-pascal wrote: I’ve been testing out all the different function pointer types in FPC to test their compatibility with each other and I noticed that “is nested” can accept a global function declaration but “of object” can not. What is the reason for this exactly? I wouldn’t expect nested function types to accept global functions but since they do I wonder why “of object” is different. Because you're pushing a parameter which does not exist in the case of a global function. I think they both have a hidden first parameter (like self) and nested types simply ignore this for global functions so I would think objects types could do the same. I cannot comment on the 'is nested', I don't know what the extra field is for. I assume a parent stack frame pointer, which can perfectly be nil, presumably. A method pointer is actually 2 fields, both pointers: the data (self) and the address (location of method). Because you cannot distinguish between 'self = nil' and 'there is no self' when actually calling the method, it's not possible to assign a global method: you would be pushing a 'self' parameter to a procedure that is not expecting a 'self' parameter, wreaking havoc on the stack. Theoretically one could add a third field, or maybe encode a special value to distinguish between the two, but then you would need to add some logic at every call of an 'of object' method to determine what is needed. That would slow things down, and would be not be Delphi compatible. There is plenty of code out there that assumes the current mechanism to 'just work' Similarly, you could let all global methods accept a 'self' pointer which is simply Nil, but same argument applies: it slows things down (extra parameter to handle) and is not TP nor Delphi compatible. When starting from zero, one could probably make all 3 methods (plain procedure, 'of object' and 'is nested' compatible - maybe even 'reference to', but for historical reasons it is not possible. Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal