I was also wondering about this. Does FreePascal support anonymous functions or alike? something like this?
x := MyFunction(procedure begin // do stuff end)
One could easily implement map, fold, etc. if functions are to become first class in FreePascal. This would also open the door for other interesting concepts, such as easy "async" execution of functions. e.g.:
context := ExecuteAsync(procedure begin // do stuff in another thread end); // do stuff context.Await;
I'm still pretty new to FreePascal, so maybe something as easy as this is already possible?
Are there functional programming methods in Pascal such as map, filter, apply, fold, foldl and foldr function? I could not find them on searching the internet. Possibly Pascal is a purely imperative language.I know great map, filter, reduce,.. from Python!
I was also wondering about this. Does FreePascal support anonymous functions or alike? something like this?As marcov wrote this is not yet possible, but you can do something like this (needs FPC 3.2.0 or newer):
x := MyFunction(procedure begin // do stuff end)
One could easily implement map, fold, etc. if functions are to become first class in FreePascal.
What is the problem that anonymous functions solve? I don't get it.
What is the problem that anonymous functions solve? I don't get it.In this specific case they allow you to define the function "inline". My example from above (shortened), but with anonymous functions:
What is the problem that anonymous functions solve? I don't get it.If you ever used a functional programming language like Haskell then you will miss them ;D. They are especially useful for writing async or concise code that doesn't jump (spaghetti) all over the place, so it's easier to maintain. They are also very suited for one off functions, e.g. specific sort functions or a small block of code that you need often inside a single function but which doesn't deserve a place in the namespace because it is too specific.
Something like this?Very cool, I'll be using this until it lands. Do you know if the function gets inlined by fpc automatically, or do I have to declare it as inline?
function IsNegative(SomeParam: Integer): Boolean; var SomeVar: Integer; function Calculate: Boolean; begin Result := False; if SomeVar < 0 then Result := True; end; begin Result := Calculate; end;
They copies it from Pascal ;)
Due to the syntax of anonymous functions that looks a bit convoluted and once the functionality of anonymous functions is integrated into trunk I want to play around with a simpler syntax like this:This would be nice if it's possible.This would require type inference for the lambda type and thus a new concept for Pascal so I'm a bit reluctant here, but I'll play around with it nevertheless.
arr := specialize Map<LongInt>(lambda (aElem) as aElem * 2, [3, 5, 6, 8]);
PascalDragon, I do understand that you can make your code less readable by fitting everything on a single line. But is there any new functionality?
type TMyFunc = function(aArg: LongInt): LongInt is reference; function GetFunc(aArg: LongInt): TMyFunc; var tmp: LongInt; begin tmp := aArg * 2; Result := function(aArg: LongInt): LongInt begin Result := aArg * tmp; end; end;
Use of anonymous functions is a matter of style. Using them is never the only way to solve a problem; each anonymous function could instead be defined as a named function and called by name.
In your example, what is the actual result? A number, a pointer to a function or something else?The type of Result in the example is a function reference (see the declaration of TMyFunc). And that function reference can then be called somewhere else. You can think of it like a function or method variable, but with a bit more magic behind the scenes involved.
PascalDragon, I do understand that you can make your code less readable by fitting everything on a single line. But is there any new functionality?
Didn't you read what I wrote? It allows for functions together with state to be passed around outside of the scope they were declared in. Somewhat like nested functions, but not restricted to their point of declaration.
This feature superficially remembers me of Computer Associate Clipper's Eval(), AEval() and DBEval():PascalDragon, I do understand that you can make your code less readable by fitting everything on a single line. But is there any new functionality?Yes, there is.
You obviously missed the point from PascalDragon's examples.
Read his examples more carefully, see in the last example, that you can for instance generate a functions with one parameter, depending on some other parameter (local var from other function, or whatever).
type TMyFunc = function(aArg: LongInt): LongInt is reference; function GetFunc(aArg: LongInt): TMyFunc; var tmp: LongInt; begin tmp := aArg * 2; Result := function(aArg: LongInt): LongInt begin Result := aArg * tmp; end; end;
Actually, I very much agree with you about lesser readability, but yes, there is actually new functionality.
The bad thing is that people will use it all over the place, when not actually needed, which will do nothing else but make the code less readeable.
It should be used sparingly.
This feature superficially remembers me of Computer Associate Clipper's Eval(), AEval() and DBEval():What that "feature" reminds me of is the old COBOL "ALTER" statement which allowed a programmer to alter (pun fully intended) the target of a goto. Someone figured that a simple "GOTO" wasn't bad enough, with "ALTER" not only the programmer could "GOTO" just about anywhere in the program but the target of the "GOTO" could only be known at run time. goto-s "al-dente" with lots of marinara sauce (nose bleed) and a thick layer of parmesan (aspirin gewk). Great stuff :)
Three or two decades ago, that feature eased a lot to get the job done for a very few of us, but became a real nightmare in maintenance for many programmers not that high skilled.I always thought that the mark of a highly skilled programmer is the ability to produce code that is easy to maintain for the average programmer.
I always thought that the mark of a highly skilled programmer is the ability to produce code that is easy to maintain for the average programmer.And to make sure all the interfaces are defined and used. Bonus points if that is easier than using the quick-and-dirty way.
Is a function reference different from a function pointer? And is the state that the parameters are already filled?Yes, it's different, because a function pointer is only a single CodePointer. Compare that to a method pointer which is in fact a TMethod containing both a function pointer and the Self pointer. A function reference is again different, because it also contains space for all the captured variables from the outer scope that is kept alive until the last function reference goes out of scope.
Behind the scenes it's an interface with only an Invoke() method that's implemented by a class instance. This class instance is shared by all anonymous functions of a single scope. Though this is all an implementation detail.
Btw, about the readability:
A few years ago, I was working on a C# ASP.NET webapp. And the lead designer spend his time with Resharping all the source code. And he turned on all the options. So, when I made some beautiful, readable and maintainable code, he turned it in an unreadable and unmaintainable mess of nested LINQ queries (Lambda functions, or anonymous functions).
e.g. type inference.
generic function DoStuff<T>(a, b: T): T; begin Result := a + b; end; procedure MyProcedure; var A, B, X: Integer; begin A := 1; B := 2; X := DoStuff(A, B); // no need to specialize DoStuff, compiler can infer type and specialize automatically. end;
e.g. anonymous function with lambda syntax is clear and concise.
procedure MyProcedure; var L: MyList; // TMyList<MyObject> begin L.Sort(lambda (a, b) as Result := a.X > b.X); end;
That kind of type inference for generics is actually already fully implemented, BTW. It's currently just waiting on being merged to trunk.
What bothers me most about Lambda functions is, that their syntax is entirely different from everything around it. It is a second, embedded language.
Like, you have two vars, a and b, but they're not actual vars. They are like magic. Consider this instead:
And in your example, you could simply write:
procedure MyProcedure; var L: MyList; // TMyList<MyObject> begin L.Sort; end;
That would have the exact same effect.
procedure MyProcedure; var L: MyList; // TMyList<Person> begin L.Sort(lambda (a, b) as Result := a.Age > b.Age); // or L.Sort(lambda (a, b) as Result := a.Position > b.Position); end;
procedure MyProcedure(var L: TMyList<Person>); begin L.Sort('Age'); // or L.Sort('Position'); end;
It is needed for Delphi compatibility as there is code out there that (ab)uses this implementation detail. Also it's necessary for the lifetime management of the state (it *could* be done some other way, but why implement something new if existing functionality can be used).Behind the scenes it's an interface with only an Invoke() method that's implemented by a class instance. This class instance is shared by all anonymous functions of a single scope. Though this is all an implementation detail.
While I certainly want anonymous functions in FPC sooner than later, I really wish they weren't implemented this way (which not only makes them un-inlinable but also requires heap allocation.)
Hopefully that can be optimized / remedied at some point after the initial implementation is merged, though. Having FPC be able to inline normal procvars would be a nice also.
I think the syntax with 'lambda' and the 'as' suits pascal, but maybe someone can come up with a better pascal-esque syntax for lambdas that would fit even better into the language?There needs to be some keyword that lets the compiler decide whether it should parse a lambda function or not. I already have enough problems with implementing Delphi generic specialization with their oh so ambiguous syntax (especially as generic types can be overloaded with constants and variables).
Please note that the idea is that the right side of the as is an expression, not a statement, so it would be
procedure MyProcedure; var L: MyList; // TMyList<Person> begin L.Sort(lambda (a, b) as Result := a.Age > b.Age); // or L.Sort(lambda (a, b) as Result := a.Position > b.Position); end;
What bothers me most about Lambda functions is, that their syntax is entirely different from everything around it. It is a second, embedded language.They consist of Pascal expressions, so what exactly is a second language here?
Like, you have two vars, a and b, but they're not actual vars. They are like magic.No, they're parameters. It's simply part of the lambda's syntax:
LAMBDA::=lambda [(LAMBDABPARAMS)] as EXPR
LAMBDAPARAMS::=LAMBDAPARAM[;LAMBDAPARAMS]
LAMBDAPARAM::=IDENTLIST[:TYPE]
IDENTLIST::=IDENTIFIER[,IDENTIFIER]
Edit: If you REALLY want Lambda functions, do it like this:This is not a lambda function. It's seems you still don't get the conceptual idea behind lambdas/anonymous functions.
for s1, s2 in MyStringList step 1 do ..
procedure MyProcedure(var L: TMyList<Person>); begin L.Sort('Age'); // or L.Sort('Position'); end;
What exactly is this supposed to be doing?
It is needed for Delphi compatibility as there is code out there that (ab)uses this implementation detail. Also it's necessary for the lifetime management of the state (it *could* be done some other way, but why implement something new if existing functionality can be used).
The inlining is also only useful in a very small number of cases. Most often anonymous functions are passed to other functions/classes (e.g. as the Execute function for TThread) and then you can not inline anymore as you're essentially dealing with function pointers then. In my opinion it's wasted time to add support for inlining anonymous functions.
What I meant was that a function or procedure that takes an anonymous function as an argument, and specifically does not capture state but simply makes use of the return value, is negatively impacted performance-wise if the anonymous function still requires heap allocation no matter what.But the code that gets passed such an anonymous function can not differentiate whether the function got state or not. In fact in one case it can be called with a function reference that has state and in another with one that doesn't. So there is only one way that the code calling the anonymous function can call said function: by treating the function reference as an interface and calling Invoke.
It is simply not true that there is any legitimate technical reason that function pointers cannot be inlined, though. I can't really think of a compiler for any "native" language other than FPC (and Delphi) that doesn't do so. (I've actually looked into what it would take to implement it in FPC myself, and the only thing that seems to make it difficult at all is the fact that "procvardefs" have an overly-limited amount of information associated with them versus "procdefs".)Yes, there is a technical reason: namely if the compiler can not proof that it can simplify it. Your example is an explicit situation where it would also be possible in FPC (if the compiler would support it). Even your example would however fail if you'd split the functions across compilation units (with Link Time Code Generation or whatever the term is for LLVM disabled).
For example, here's a small C++ proram showing that both C++11 lambdas and also "classic" function pointers are indeed fully inlineable:
https://godbolt.org/z/BPdOI6 (https://godbolt.org/z/BPdOI6)
The same program in Swift: https://godbolt.org/z/72uzPw (https://godbolt.org/z/72uzPw)Again same problem as in C++. As soon as you get to more real world examples and also apply the conceptual restrictions of Object Pascal that all breaks apart.
And in Rust: https://godbolt.org/z/7h0ssB (https://godbolt.org/z/7h0ssB)
Also in C (with no anonymous function obviously, just the function pointer): https://godbolt.org/z/hX76pQ (https://godbolt.org/z/hX76pQ)
And lastly in D: https://godbolt.org/z/N5o46p (https://godbolt.org/z/N5o46p)
In all cases, no heap allocation is required for the non-capturing anonymous function, and the use of both it as well as the "normal" function pointer is inlined completely.
Again same problem as in C++. As soon as you get to more real world examples and also apply the conceptual restrictions of Object Pascal that all breaks apart.
it's something I think would have extremely far-reaching end-user benefits.
This is not a lambda function. It's seems you still don't get the conceptual idea behind lambdas/anonymous functions.
LAMBDA::=lambda [(LAMBDABPARAMS)] as EXPR
LAMBDAPARAMS::=LAMBDAPARAM[;LAMBDAPARAMS]
LAMBDAPARAM::=IDENTLIST[:TYPE]
IDENTLIST::=IDENTIFIER[,IDENTIFIER]
Behind the scenes it's an interface with only an Invoke() method that's implemented by a class instance. This class instance is shared by all anonymous functions of a single scope. Though this is all an implementation detail.
ANONFUNC::=FUNCHEADER|PROCHEADER BLOCK
FUNCHEADER::=function[(PARAMLIST)]:TYPE DIRECTIVES
PROCHEADER::=procedure[(PARAMLIST)]:TYPE DIRECTIVES
PARAMLIST::=PARAMDECL[;PARAMLIST]
PARAMDECL::=PARAMIDENTLIST:TYPE
PARAMIDENTLIST::=[var|const|out|constref|] IDENTIFIERLIST
IDENTIFIERLIST::=IDENTIFIER[,IDENTIFIERLIST]
By the way: the syntax for anonymous functions with function and procedure is non negotiatable as that syntax is needed for Delphi compatibility.
In this lambda syntax the parameter types and the result type are not declared explicitely? :oYes, that would require type inference. That's why I said that I'm still sceptical about adding this syntax at all. On the other hand it allows for a much more compact syntax, especially for simple lambda expressions (just compare the two examples I've given).
Only now I noticed that. May I hope it will never get into our language.
In this lambda syntax the parameter types and the result type are not declared explicitely? :oYes, that would require type inference. That's why I said that I'm still sceptical about adding this syntax at all. On the other hand it allows for a much more compact syntax, especially for simple lambda expressions (just compare the two examples I've given).
Only now I noticed that. May I hope it will never get into our language.
Just curious... couldn't the example you gave be implemented without having to use type inference ... something along the lines of ...It isn't as concise as the construct you showed but, it seems to be more in tune with the Pascal way.
var l: TList<TPerson>; begin l.Sort( lambda (aLeft, aright : TPerson) : boolean as aLeft.Age < aRight.Age ); end.
Then, what is the problem with:I don't see a problem with it. I think it is perfectly fine.:)
var l: TList<TPerson>; begin l.Sort( function(aLeft, aright: TPerson): Boolean; begin Result := aLeft.Age < aRight.Age end ); end.
Yes, that's the problem if one does not use type inference: Then there is basically no real difference to the syntax that Delphi has.
Just curious... couldn't the example you gave be implemented without having to use type inference ... something along the lines of ...It isn't as concise as the construct you showed but, it seems to be more in tune with the Pascal way.
var l: TList<TPerson>; begin l.Sort( lambda (aLeft, aright : TPerson) : boolean as aLeft.Age < aRight.Age ); end.
Then, what is the problem with::)
var l: TList<TPerson>; begin l.Sort( function(aLeft, aright: TPerson): Boolean; begin Result := aLeft.Age < aRight.Age end ); end.
Note similar is already possible with function pointers. In that sense it is syntactic sugar anyway.For that specific example this is true. However with anonymous functions you can also have state attached to the "function pointer" and pass the pointer plus the state (together a "function reference") to some outer scope.
(before overuse of anonymous methods, specially for threading, also check this thread:Marco, that thread has nothing to do with anonymous methods and/or threading.
https://forum.lazarus.freepascal.org/index.php/topic,45927.msg325474.html#msg325474 )
(before overuse of anonymous methods, specially for threading, also check this thread:Marco, that thread has nothing to do with anonymous methods and/or threading.
https://forum.lazarus.freepascal.org/index.php/topic,45927.msg325474.html#msg325474 )
Note similar is already possible with function pointers. In that sense it is syntactic sugar anyway.For that specific example this is true. However with anonymous functions you can also have state attached to the "function pointer" and pass the pointer plus the state (together a "function reference") to some outer scope.
... pass the pointer plus the state (together a "function reference") to some outer scope.scope level jumping/referencing... isn't that the very essence of spaghetti code ? (not even taking into account the difference timing in variable capture can make.)
I hope I understood this feature, please correct me if not.Yes, you understood it correctly. And yes, the D is essentially the state of the function reference.
They allow you for example to easily set up a thread without the need to declare a whole class:... pass the pointer plus the state (together a "function reference") to some outer scope.scope level jumping/referencing... isn't that the very essence of spaghetti code ? (not even taking into account the difference timing in variable capture can make.)
I think it's fine and, sometimes even desirable, to have a way to define and use function/procedures inline but, letting references to them leak out of the scope they are defined in, not even Italians make spaghetti that jumps from one plate to another.
It seems to me that, lambas - as currently implemented - are an idea/method, from someone who coded themselves into a corner, who needed someway to get themselves out of the mess they made.
They allow you for example to easily set up a thread without the need to declare a whole class:There is no doubt there are cases, like the example you presented, where that syntax results in something that is clean and easier to maintain than the traditional alternative but, it also opens the door to some rather "poor" constructions.At work - where we use C++ - I use their C++ equivalent very much, because they essentially allow to keep code together that conceptually belongs together (though more often than not I also use them, because C++ does not know nested functions :-[ )
procedure DoSomethingAsynchronous(aObj: TMyWorkObject; aEvent: TEvent); begin TThread.CreateAnonymousThread(procedure begin DoSomethingWithWorkObject(aObj); aEvent.SetEvent; end); end;
There is no doubt there are cases, like the example you presented, where that syntax results in something that is clean and easier to maintain than the traditional alternative but, it also opens the door to some rather "poor" constructions.Any feature opens the door for "poor" constructions. Anonymous functions aren't anything special there. If a feature exists it's going to be abused.
Any feature opens the door for "poor" constructions. Anonymous functions aren't anything special there. If a feature exists it's going to be abused.Yes, that is true but, some constructions lend themselves much better for building atrocities than others. Lambdas are among them. The only example I've seen of a nice use of a lambda I can think of, is the one you gave in this thread. The other uses I've seen go from "I can do that just as cleanly and easily without a lambda" to "another sample of logical epilepsy".
How do you track which threads are still active, and how do you distribute the pointers?
So, you have multiple threads and a queue, the threads do their thing and when they are done, they call a synced method in the main prog, after which they try to read the next job from the queue?
Are there standard components for that? It's always a lot of work to build.