Does Free Pascal have anonymous functions that you can pass around, e.g. to a sort(compare : function, arr : array) function?
If not, does anyone know any hacks to accomplish this?
Cheers,
Andrew Pennebaker
www.yellosoft.us

Mailing lists / fpc-pascal / 2011-10
125 messages · 30 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
Does Free Pascal have anonymous functions that you can pass around, e.g. to a sort(compare : function, arr : array) function?
If not, does anyone know any hacks to accomplish this?
Cheers,
Andrew Pennebaker
www.yellosoft.us
Andrew Pennebaker wroteDoes Free Pascal have anonymous functions that you can pass around, e.g. to a sort(compare : function, arr : array) function? If not, does anyone know any hacks to accomplish this?
No, FPC does not support this currently and I know no one who plans to support it in the near future.
A similiar feature available in the upcoming 2.6 and in trunk are "nested function references". I wrote about that some days ago in this mail: http://www.hu.freepascal.org/lists/fpc-pascal/2011-October/030460.html
Regards,
Sven
Does Free Pascal have anonymous functions that you can pass around, e.g. to a…
Yes:
//you can declare a type :
TMyFunction: function(AMyParam : TType): TOtherType;
// then implement:
function MyFunctionWithArbitraryName(AMyParam: TType): TOtherType;
begin
{do something with AMyParam}
end;
//then (or before, if the TMyFunction is in type declaration section)
function AFunctionUsingTMyFunctionAsArgument(AFunction : TMyFunction):TWhateverType;
var OtherReturn: TOtherType;
AParameterToAFunction : TType;
begin
{some code}
OtherReturn := AFunction(AParameter);
{other code}
end;
// and finally even
const MYFUNCTIONCOUNT = 1
ArrayOfTMyFunction = array[0..MYFUNCTIONCOUNT-1] of TMyFunction = (MyFunctionWithArbitraryName);
{it's a static array, so match the number of elemets}
begin
for {declared somewhere global} i := 0 to MYFUNCTIONCOUNT-1 do
WhateverReturn := AFunctionUsingTMyFunctionAsArgument(ArrayOfTMyFunction[i](MyParam));
end.(Terms and conditions : this is invoked from /dev/mem, some syntax discrepancies may occur as my attention moved on from this as it obviously worked)
I have written a dumb CLI interpreter this way ;) recently. (the function table contains command name as string in a record together with the function and the main procedure looks for the name and executes the arbitrary function when found)
TMyFunctionRecord = record
CLIName: string;
MyFunction : TMyFunction
end;
const ArrayOfCLIFunctions = array[0..CLIFUNCCOUNT-1] of TMyFunctionRecord = ({...});
var CLIFunctionToExecute : TMyFunction;
WhateverReturn : TWhateverType;
begin
for i := 0 to CLIFUNCCOUNT-1 do
if ArrayOfCLIFunctions[i].CLIName = paramstr[1] then
begin
CLIFunctionToExecute := ArrayOfCLIFunctions[i].MyFunction;
break;
end;
WhateverReturn := AFunctionUsingTMyFunctionAsArgument(CLIFunctionToExecute(MyParam));
end.Also the 'anonymous' functions can be implemented in a separate unit which only exports the /relevant/ ones in its interface section.
The obvious limitation / safeguard is : you must use the function of declared type to pass into the function AFunctionUsingTMyFunctionAsArgument(AFunction : TMyFunction) and no other type; (An obvious workaround to that is to use varargs ;) but I did not try that so I can't tell whether that would work)
It's not much OOP in action (and may have {obvious for some //not me} performance penalties but oh well. ;)
L.
[...]
(facepalm)
I did not try 'anonymous' function as you asked, oh. Need to learn to read ;)
L.
Yes: //you can declare a type : TMyFunction: function(AMyParam : TType): TOtherType; //…
Sokol, I'm writing a function GenArray(generator) that returns a random array populated by calling the generator function. So the return type of GenArray matches "array of" the return type of the generator function, for any generator function.
E.g., GenArray(GenChar) would return a random string. (Except I don't know the syntax for passing function pointers.)
Maybe you could fork my code and use templates to achieve this?
GitHub <https://github.com/mcandre/paycheck>
Cheers,
Andrew Pennebaker
www.yellosoft.us
Sven pointed out yesterday that you cannot achieve in FPC what you want to achieve. (I haven't used Delphi in a long time and don't know what exactly anonymous functions are in Delphi, but I strongly tend to trust his word.) You can't get anonymous but only typed "function pointers" (cf. also Lukasz mail, second to last paragraph, plus his short mail).
Since you were asking for hacks... By way of satire(!): To bypass the need to explicitly define a function type for each data type, you could give up on types and write a lot of functions like
function GenChar : Pointer;
function GenString : Pointer;The type of all of those can be given as
type TGen = function : Pointer;Generator would have to return an array of Pointer in this scenario. Then, you could hack your way on from there. Please don't mention my name, though.
However, if you're just asking about the syntax for procedural types, the "Language reference guide" for FPC 2.4.4, section 3.6 (p. 45) has all the details: http://www.freepascal.org/docs.var
Maybe you could fork my code
Out of curiosity: Is that the impersonal "you"?
and use templates to achieve this?
Generics are currently for classes only, as chapter 8 (p. 87) of the aforementioned reference guide explains.
Best,
Roland
Sokol, I'm writing a function GenArray(generator) that returns a random array populated…
anonimous types, thrice, generic array concatenation, interpreting Pascal, anonymous functions...
I'm guessing what language you come from.
Then, the second question arises: why Pascal, now.
Anyway, I think that immersing yourself in some classes and pointer logic could help you find some solutions to your tasks. (I still, anyway, suggest the quick and dirty C way with its macros and includes...)
Cheers, A.
Sven pointed out yesterday that you cannot achieve in FPC what you want to achieve. (I…
For anonymous functions you can take a look at Embarcadero's Delphi help here:
http://docwiki.embarcadero.com/RADStudio/en/Anonymous_Methods_in_Delphi
Regards,
Sven
Sven pointed out yesterday that you cannot achieve in FPC what you want to achieve. (I…
Schäfer, thanks, that's a lot of practical information. Have you used Haskell QuickCheck<http://www.haskell.org/haskellwiki/Introduction_to_QuickCheck>? It's amazing that such a strictly typed language can do these sorts of things.
Yes, pointers are probably the only way I can implement this, for now. If at all possible, I'd like to use more idiomatic Pascal code. The only way I managed to write the C port <https://github.com/mcandre/qc> was void* tricks :P but there's only so much you can do without lambdas.
If I decide to use pointers, what's the syntax for accepting a function pointer (unknown type, unknown arity) and calling the function? In C, you have to know the entire function signature and explicitly cast the pointer to that before you can call it. Does Pascal also require this, or can I just accept a pointer and call it as if it were a normal function call?
Finally, does Pascal have syntax for something like Lisp's (apply f args), or Smalltalk's Block valueWithArguments? Once I get forAll to accept function pointers, and call the functions, I need a way to pass the values to another function (again, unknown types, unknown arity).
Cheers,
Andrew Pennebaker
www.yellosoft.us
2011/10/18 Roland Schäfer
Andrew Pennebaker wroteSchäfer, thanks, that's a lot of practical information. Have you used Haskell QuickCheck
In fact, I have, but I don't see the connection.
Yes, pointers are probably the only way I can implement this, for now. If at all possible, I'd like to use more idiomatic Pascal code.
Those sentences form a contradiction.
but there's only so much you can do without lambdas.
I saw the l-word coming.
If I decide to use pointers,
... you'll end up on CodeSOD.
what's the syntax for accepting a function pointer (unknown type, unknown arity) and calling the function? In C, you
In Pascal, you use procedural type variables, not function pointers; it makes a conceptual and a practical difference. Procedural type variables have a type (hence the name). You can push them around as untyped Pointers, but you shouldn't. My *joke* was about turning the result type of your functions into Pointer, so all your GenSomething functions are of the same procedural type and can thus be accepted as an argument by your generator... with virtually unusable results. Please, RTM.
In C you have to know the entire function signature and explicitly cast the pointer to that before you can call it. Does Pascal also require this, or can I just accept a pointer and call it as if it were a normal function call?
If you read the aforementioned reference and meditate about it, you might notice why you don't have to cast procedural type variables in Pascal.
Regards,
Roland
The procedural types<http://www.freepascal.org/docs-html/ref/refse17.html#x45-520003.6>doc is informative, thanks for the suggestion.
Eh, much humor will be lost on me. I'm a Pascal newbie, so if you suggest function pointers, even with (satire!) comments, that's what I'll use. Pointers do the job in C, why shouldn't they in Pascal?
There are CodeSOD hacks, and there are necessary hacks. If you don't like the void* trickery in qc <https://github.com/mcandre/qc>, issue a pull request.
Cheers,
Andrew Pennebaker
www.yellosoft.us
2011/10/18 Roland Schäfer
For anonymous functions you can take a look at Embarcadero's Delphi help here:…
Sven Barth wroteFor anonymous functions you can take a look at Embarcadero's Delphi help here: http://docwiki.embarcadero.com/RADStudio/en/Anonymous_Methods_in_Delphi
The Embarcadero style of anonymous functions does not satify me.
myFunc := function(x, y: Integer): Integer
begin
Result := x + y;
end;This is not easier than writing:
function Bla(x, y: Integer): Integer
begin
Result := x + y;
end;
myfunc := @Bla;I would prefer a style like
myfunc := @function(x, y: Integer): Integer Result := x + y;But this makes it hard to read. Of course it would be nice to have anonymous functions or even lambdas (think about integrated languages like LinQ). But maybe Pascals strength of easy readable code gets lost.
Michael
Michael Fuchs wroteI would prefer a style like myfunc := @function(x, y: Integer): Integer Result := x + y;
And how would you create more complex functions? In Pascal code blocks are started with "begin" and ended with "end". I don't see a reason why anonymous methods should differ here.
Also the example given by Embarcadero is a bit boring. The interesting thing about anonymous methods (and nested functions types in FPC) is that they can access variables of the surrounding function (at least I hope that I've understand it correctly that nested function types can do that).
E.g.
TIntegerFunc = reference to function: Integer;
procedure SomeOtherProc(aFunc: TIntegerFunc);
...
procedure Foo;
var
x: Integer;
begin
x := 42;
SomeOtherProc(function: Integer; begin Result := x; end;);
end;I haven't tested that, but from the description that should work.
The FPC equivalent should be (not tested as well):
type
TIntegerFunc = function: Integer is nested;
procedure SomeOtherProc(aFunc: TIntegerFunc);
...
procedure Foo;
var
x: Integer;
function ReturnX: Integer;
begin
Result := x;
end;
begin
x := 42;
SomeOtherProc(@ReturnX);
end;Regards,
Sven
Sokol, I'm writing a function GenArray(generator) that returns a random array populated…
Hi Andrew,
first of all my /first/ name is Lukasz. Would you /like/ me to use your surname to refer to yourself ?
Second you seem to be sending the same message twice in one post (once as plain text the other as HTML) and quoted/printable encoding to make matters even worse. Please teach your (gmail ?) to behave.
Third you're top-posting and this is is a no-no to many; We're not your corporate friends who are on top of things by definition, we have our lives and we read from the beginning to refresh on the matter.
Fourth, you're leaving too much of the quote below your answer, for what exactly? Save electrons, they are becoming scarce.
Fourth and I won't go into technicalities here but what is it exactly you want to achieve by trying to make FPC bend over backwards ?
L.
On 18/10/2011 19:10, Andrew Pennebaker wrote:
[...cut quote...]
And how would you create more complex functions? In Pascal code blocks are started with…
Allow both, like it is already allowed in Pascal:
if True then DoSomething;
if True then begin
DoSomething;
DoSomethingMore;
Etc;
end;If a function only contains one statement it is not a codeblock.
Michael
And how would you create more complex functions? In Pascal code blocks are started with…
19.10.2011 12:16, Sven Barth пишет:
But _real_ functional equivalent of Delphi's function reference if COM-interface based functor.
F.e.
"TMyFuction = reference to function: Integer; "
and
"IMyFunction = interface
function Invoke:Integer;end;"
Hmm... I'm not really sure though, but I guess you could make use of "array of const" feature. See the documentation here:
http://www.freepascal.org/docs-html/ref/refsu60.html
And how would you create more complex functions? In Pascal code blocks are started with…
The main difference between anonymous methods and nested functions is that one can return a reference to an anonymous method from a function, the anonymous method can access local variables from that function and even after exiting the function, the variables are still valid. This means that local variables accessed in a anonymous method end up on the heap.
However, I fail to see reasonable use cases for anonymous methods
Practical uses for referencable anonymous functions:
(map f collection)
This is the prototypical way to run a function over each element in a collection, returning the results.
Example:
(map (lambda (x) (+ x 1)) '(1 2 3))
-> (2 3 4)
(sort compare collection)
When dealing with complex data types, the user may want to implement a custom compare function.
(sort (lambda (x y) (- y:employee-id x:employeeid)) (list emp1 emp2 emp3))
-> (emp3 emp1 emp2)
(zip f collection1 collection2)
Similar to map, zip runs a 2-input function over the elements of the collections, returning the results.
(zip (lamba (x y) (+ x y)) '(1 2 3) '(4 5 6))
-> (5 7 9)
At first glance, each of these examples may seem pointless. Can't we implement the same behavior without referencing anonymous functions? Yes, we can, but only for a specific function. If you want your database library to allow users to customize sorting, you'll need referencable anonymous functions.
If you've used a functional language, you know how powerful these little functions are, and you'll miss them and want to implement them in languages that don't have them.
Cheers,
Andrew Pennebaker
www.yellosoft.us
Andrew Pennebaker wrotePractical uses for referencable anonymous functions:
For such applications one uses procedure variables in pascal.
I still don't see why this cannot be done by procedure variables: one can easily pass a procedure reference to a compare function to any sort library call. The example is far from explaining why it is needed to be able to return a reference to an anonymous method to the outside of the enclosing function.
Florian Klämpfl wroteI still don't see why this cannot be done by procedure variables: one can easily pass a procedure reference to a compare function to any sort library call.
It is maybe easier to write a anonymous function inline than declaring a function and passing it with a reference to this function.
Sometimes I miss them in FPC, but I am also not sure if this feature destroys the beauty of Pascal.
Not easy.
Michael
For such applications one uses procedure variables in pascal. I still don't see why this…
From what I gather, procedure variables can indeed be referenced and passed
around, etc.
However, procedures do not return anything, so it's hard to chain them. In functional languages, it's handy to do several nested map(map(map f ... calls.
Cheers,
Andrew Pennebaker
www.yellosoft.us
Pascal isn't a functional language. You'll need to find other ways to do this in Pascal as other Pascal users have found ways to implement their code. You could try object oriented programming for example (though I don't know a specific solution for "map").
Regards,
Sven
around, etc. However, procedures do not return anything, so it's hard to chain them. In…
Andrew Pennebaker wroteHowever, procedures do not return anything, so it's hard to chain them. In functional languages, it's handy to do several nested map(map(map f ... calls.
So just make a function instead of a procedure?
around, etc. However, procedures do not return anything, so it's hard to chain them. In…
Andrew Pennebaker wrote>From what I gather, procedure variables can indeed be referenced and passed around, etc. However, procedures do not return anything, so it's hard to chain them.
They are called procedure variables but can also contain functions.
In functional languages, it's handy to do several nested map(map(map f ... calls.
For such applications one uses procedure variables in pascal. I still don't see why this…
----- Original Message -----
[snip!]
[not_sure_if_serious.png]
Interesting discussion -- at least for me, I didn't know Delphi had this feature.
In case anyone really doesn't see the point, consider that this thing:
http://www.youtube.com/watch?v=cYw2ewoO6c4
has all the capabilities of Object Pascal (with less flowery syntactic sugar to mess up the purity of the system).
:P
If anybody does not see why increasing complexity without a good reason should be avoided, I recommend:
----- Original Message -----
:)
Good point. I guess nothing's O(free lunch).
If anybody does not see why increasing complexity without a good reason should be…
2011/10/20 Florian Klämpfl
:-)
There is lots of confusion about anonymous functions. The name is misleading, they are called closures in other languages. There was a similar discussion earlier, see :
http://www.hu.freepascal.org/lists/fpc-pascal/2010-January/023755.html
The origin is from functional languages but it is fine to borrow it to OP, the same way classes and object features were borrowed earlier from other languages. Besides I think the closure addition is almost as important.
They have some very important uses, like making multithreading easier. I copy text from Delphi help page again here because it looks so cool:
--------------------------------------------------------- Using Code for a Parameter
Anonymous methods make it easier to write functions and structures parameterized
by code, not just values.
Multithreading is a good application for anonymous methods. if you want to execute
some code in parallel,
you might have a parallel-for function that looks like this:
type
TProcOfInteger = reference to procedure(x: Integer);
procedure ParallelFor(start, finish: Integer; proc: TProcOfInteger);The ParallelFor procedure iterates a procedure over different threads.
Assuming this procedure is implemented correctly and efficiently using threads
or a thread pool, it could then be easily used to take advantage of multiple processors:
procedure CalculateExpensiveThings;
var
results: array of Integer;
begin
SetLength(results, 100);
ParallelFor(Low(results), High(results),
procedure(i: Integer) // \
begin // \ code block
results[i] := ExpensiveCalculation(i); // / used as parameter
end // /
);
// use results
end;Contrast this to how it would need to be done without anonymous methods: probably a "task" class with a virtual abstract method, with a concrete descendant for ExpensiveCalculation, and then adding all the tasks to a queue--not nearly as natural or integrated.
Here, the "parallel-for" algorithm is the abstraction that is being parameterized by code. In the past, a common way to implement this pattern is
with a virtual base class with one or more abstract methods; consider the TThread class and its abstract Execute method. However, anonymous methods make
this pattern--parameterizing of algorithms and data structures using code--far
easier.
Regards,
Juha Manninen
----- Original Message ----- :) Good point. I guess nothing's O(free lunch). -gmt
2011/10/20 Gregory M. Turner
Good point. I guess nothing's O(free lunch).
Yes, the downside here is that the concept is very different from any syntax in OP. It will be difficult to learn properly.
Juha
2011/10/20 Florian Klämpfl :-) There is lots of confusion about anonymous functions. The…
Juha Manninen wroteThey have some very important uses, like making multithreading easier. I copy text from Delphi help page again here because it looks so cool:
The same can be done with fpc (nested if needed) procedure variables and it will be more readable (imo)? The example still does not take advantage of properties of anonymous methods/closurs which cause complexity like being ref. counted, putting locals on the heap etc.
If anybody does not see why increasing complexity without a good reason should be…
+1000000000000~
;)
2011/10/20 Gregory M. Turner Yes, the downside here is that the concept is very different…
i still fight, today, with much of my LISP code... :? :(
If anybody does not see why increasing complexity without a good reason should be…
If anybody does not see why increasing complexity without a good reason should be avoided, I recommend:
http://www.youtube.com/watch?v=kYUrqdUyEpI
Lisp used for nuclear fail-safe
systems<http://books.google.com/books?id=5fbyVju-LJ8C&pg=PA75&lpg=PA75&dq=lisp+nuclear+reactor&source=bl&ots=EMUJzJKT0D&sig=LCb3KDYjiSpzh0-76R1LdJm8rJc&hl=en&ei=886gTu-sAunm0QHtmrz6BA&sa=X&oi=book_result&ct=result&resnum=3&sqi=2&ved=0CC0Q6AEwAg#v=onepage&q=lisp%20nuclear%20reactor&f=false>. I doubt languages without *map* are up to the job.
Cheers,
Andrew Pennebaker
www.yellosoft.us
If anybody does not see why increasing complexity without a good reason should be…
If anybody does not see why increasing complexity without a good reason should be avoided, I recommend:
I agree wholeheartly. In the past Pascal was a simple still powerfull language but meanwhile it has become a catchment tank for all features of all other languages. This defeats the original intention of Nicholas Wirth and the reason for what I love(d) the language. It seems everybody tries to mimic Pascal into whatever he is used to do in other languages. So we should no longer call this (Object) Pascal but "Chimera".
If anybody does not see why increasing complexity without a good reason should be…
Andrew Pennebaker wroteLisp used for nuclear fail-safe systems I doubt languages without /map/ are up to the job.
Great, why don't you continue to use lisp then? If pascal does not offers the language concepts you are used to, pascal is the wrong language for you.
I agree wholeheartly. In the past Pascal was a simple still powerfull language but…
2011/10/21 Jürgen Hestermann
Please look at some old Pascal code from 80's. Lots of shortstring manipulation with pointers. Very much comparable to C, and as prone to errors as C.
It is good to realize that Pascal would have died already without the class/object additions made by Borland.
The challenge is to add only the RIGHT features. In school I must study again C++ and they clearly did it wrong. Uhhh!
IMO the OP additions have been good so far. For example generics containers eliminate ugly type-casts. It is an improvement, clearly.
Closures seem like a powerful thing which can improve code. Now Florian mentioned that procedure variables could do the same thing. I clearly don't understand the topic enough, I must learn more.
It is funny how fashion trends also affect the evolution of programming languages.
When object oriented programming became a trend, everything had to be an object.
Java libs are a good example. Some classes (nouns) have only one method (verb) called "Execute".
Translated to human languages, it is like "man's walking executor executes" instead of "man walks".
Now the functional languages turn fashionable, maybe as a counter-effect to OO.
Some people said that programming became funny again when using a functional language (Haskel was it?).
I also want to learn and understand how to say things with only functions (verbs).
All this turbulence proves how young is the evolution of programming languages. Human languages have a much longer evolution. You can see they have a versatile syntax. They have lots of redundancy and synonyms to ensure "error free message delivery".
The syntax (grammer) is not always simple but it is expressive.
Juha
The same can be done with fpc (nested if needed) procedure variables and it will be more…
Florian Klämpfl wroteThe same can be done with fpc (nested if needed) procedure variables and it will be more readable (imo)? The example still does not take
This seldom happens, but here I fully agree with Florian. ;-) Every example of anonymous methods I have seen so far, can easily be done with OP's procedure variables too. Maybe anonymous methods were introduced in other languages because they didn't have something like OP's procedure variables. I guess Object Pascal was yet again ahead of everybody else. :)
Regards,
- Graeme -
Maybe anonymous methods were introduced
in other languages because they didn't have something like OP's procedure variables
IMO, it's because they're lazy to declare things before they use it. Often, an anonymous function which first used just once eventually used more than once. When that happens, users of languages with anonymous function would refactor the function by removing it from the anonymous context into a standalone named function, and re-pass it. Where as for Pascal style users, that's not needed because the function is already named and standalone.
Does Free Pascal have anonymous functions that you can pass around, e.g. to a…
18.10.2011 0:53, Andrew Pennebaker пишет:
Does Free Pascal have anonymous functions that you can pass around, e.g. to a sort(compare : function, arr : array) function?
anonymous functions = closures = lambdas are part of functional paradigm. object pascal itself is not functional language. But there is modern trend to design multiparadigm languages (usually OO
+ functional + imperative).
Delphi followed this trend. So the question is: should freepascal follow this trend too?
2011/10/21 Jürgen Hestermann Please look at some old Pascal code from 80's. Lots of…
Please look at some old Pascal code from 80's. Lots of shortstring
manipulation with pointers. Very much comparable to C, and as prone to errors as C.
Yes, new string types were needed. But why not doing it right in one step? Instead we now have lots of different string representations which all have their own peculiarities which everybody has to learn. To me it seems that all these changes were hasty hacks and are now cast in stone to live forever in the (object) Pascal language to annoy following generations of Pascal programmers. If things are only added and nothing is ever removed than the language becomes bloated.
It is good to realize that Pascal would have died already without the
class/object additions made by Borland.
I doubt that. I don't see any merrit in objects. You can do all the same with units that declare functions and data types. You can also build an IDE that helps you finding functions/procedure that act on special data types. There is no innovation in object oriented programming. Just the opposite: If I create a button "object" on my form that does something I would expect it to act when I click on it. But that does not happen because in the background there is still the procedural processor that goes through a sequential list of commands. Real objects would be able to act independently and can interact. But this would require a core for each object which I fail to see in the near future.
I am just thinking how a child or teenager who learns programming would think about it. He may not unterstand why you need to add "Application.ProcessMessages;" calls into loops to keep the button responsive. This is hiding away important information. Instead of OOP it should have been named DAF (Data Attached Functions) or so.
Also, why can operators be overloaded? Operators are fundamental parts of a programming language and to me it makes no sense to irk programmers by changing its meaning.
Also, why suddenly extend the meaning of := ? It should be a simple byte movement, nothing else (only exception should be number type convertion). Doing arbitrary complex things when using it does not make a clearer code. And for what reason? Just to save writing a function call? That cannot be the direction to go. Maybe we see BEGIN and END and the semicolon doing things too. How can one read such code? And how much does a new user have to learn to use the Pascal language?
It could also be that it's only a matter of documentation and learning. As many others I don't have very much time to read about and test new features. And I also don't have to. I never failed to do what I wanted and it was very speedy (unless I had to use some obscure "library" which was slow) and the code is still clear and readable.
The challenge is to add only the RIGHT features.
That's true. But now the mark is overshot already.
IMO the OP additions have been good so far. For example generics
containers eliminate ugly type-casts. It is an improvement, clearly.
I can't say anything about this because I don't know the concept.
Closures seem like a powerful thing which can improve code.
Same as for closures, I don't know them.
Now Florian mentioned that procedure variables could do the same
thing. I clearly don't understand the topic enough, I must learn more.
I see that many of these new concepts are added because people come from other languages and want to do things the same way. But often it can already be done with the existing language and even faster. I was able to code everything I wanted in the past 25 years without objects and without closures and all this other stuff. But if I now try to understand foreign code I am totally lost because here these things are used.
The link below describes two uses for anonymous methods.
I don't entirely subscribe to the (1) one, it seems to be mostly a shorthand argument.
But (2) is somewhat logical and interesting. an. funcs allow to wrap a call to a procedure together with its arguments inside a anonymous function (closure-like) and queue that in a different thread and have it executed there by RTL code.
I think that (2) is the main reason for anonymous functions, and people shouldn't assume that the use of an. funcs is the same as in functional languages. (IOW for expressions)
18.10.2011 0:53, Andrew Pennebaker пишет: anonymous functions = closures = lambdas…
----- Original Message -----
Taking these terms in the broadest sense possible, wouldn't we say that OOP is mostly a functional development paradigm?
Not a rhetorical question, I seriously am not sure.
OP's somewhat idiosyncratic requirement to put all the OOP metadata in a separate interface section of your code kind of underlines what I'm talking about. It seems to me that in OOP, whatever we might happen to do procedurally, there's a strong declarative odor to everything happening at the class/interface level.
-gmt
2011/10/22 Gregory M. Turner
Now you are mixing the well-established terms.
Functional programming paradigm is based on lambda calculus. There are no loop constructs or even variables in normal sense. There are only functions which return a value without side-effects.
In Object Pascal you must define types in interface, but it doesn't change the object oriented paradigm anyhow.
In Java or C# you don't have interface definitions but they still have the same paradigm.
Wikipedia has amazingly much info. See:
http://en.wikipedia.org/wiki/Functional_programming
On the right edge there is a list "Programming Paradigms".
Regards,
Juha
I agree wholeheartly. In the past Pascal was a simple still powerfull language but…
+1 (based on some of the recent stuff being posted :) )
This seldom happens, but here I fully agree with Florian. ;-) Every example of anonymous…
+1
----- Mail Original -----
De: "Graeme Geldenhuys"
À: "FPC-Pascal users discussions"
Envoyé: Vendredi 21 Octobre 2011 10h03:27 GMT +01:00 Amsterdam / Berlin / Berne / Rome / Stockholm / Vienne Objet: Re: [fpc-pascal] Re: Delphi's anonymous functions in Free Pascal
Florian Klämpfl wroteThe same can be done with fpc (nested if needed) procedure variables and it will be more readable (imo)? The example still does not take
This seldom happens, but here I fully agree with Florian. ;-) Every example of anonymous methods I have seen so far, can easily be done with OP's procedure variables too. Maybe anonymous methods were introduced in other languages because they didn't have something like OP's procedure variables. I guess Object Pascal was yet again ahead of everybody else. :)
Regards,
- Graeme -
In our previous episode, said:
I hinted on it in earlier procedures, but here a typical anonymous method usecase.
You are in a thread and want to call a method or procedure in a different thread. (to the mainthread or a different event driven thread)
BUT, the said function takes parameters. WDYD?
Classically, you create some record, add all paramters to it, dump it in some queue (or argument to a windows message if you play it dirty), write a procedure in the destination thread that gets the record from the queue, and calls the function with the parameters.
One can avoid doing the queue for every case by using a bit of OOP, but still you need to inherit and implement that object for every signature of a method that you want to call cross-thread this way. Loading parameters into it in the source thread, and calling the destination procedure with parameters in the execute method for the destination thread.
Using the anonymous function however, you put the call within the anonymous function block. This blocks captures all necessary state, and boom it is away.
Visually:
Problem:
call
targetobject.destinationfunction(a:integer;b:someobject;c:string);in a different thread.
Classic solution:
type // for every signature:
TMyobject = class(TpseudoClosure)
a:integer;
b:someobject;
c:string;
tgob: TTargetObject;
procedure execute; override;
end;
procedure TMyObject.Execute;
begin
tgob.destinationfunction(a,b,c);
end;
// once:
var
thrqueue :TSomeGenericThreadsafeQUeue<TPseudoClosure>;
procedure tmythread.syncfunc;
var x:TPseudoClosure;
begin
x:=getqueuecurrentthread().popitem; // get closure object from queue
x.execute;
x.free;
end;
// calling from source thread;var x : TPseudoclosure
x:=TMyObject.Create;
x.a:=a;
x.b:=b;
x.c:=c;
tboj:=targetobject;
queuefortargetthread.pushitem(x);
queuefortargetthread.queue(syncfunc); // call item async in other thread.
// tthread.queue not yet in FPCI have many such constructs in my current framework. Of course you start to double use simple objects, and not all cases use 3 parameters. It is just for the idea.
Note that tabstractclosure, the generic queue etc must also be defined, but that is so general it could be in the RTL, and not a burden
---------------------------------
vs
-~-------------------------------
Equivalent solution with anon functions:
targethread.queue(
procedure(targetobject:ttargetobject;a:integer;b:someobject;c:string)
begin
targetobject.destinationprocedure(a,b,c);
end;Note how common this looks compared to the original.
Btw: I don't know this function this well. I only described it how I saw it in several D2010 blogs. I still support D2009, and the framework design was even older, so I don't actively use it.
[snip]
One point is that you could do the above with a local (and named) procedure as well, and still have all the context. At the very least you would not be raping pascal's readability by putting a complete procedure declaration inside a code block.
I don't know about you, but I have serious trouble reading the above monstrosity. It looks like you forgot the closing ) for the queue call.
Michael.
In our previous episode, said:
One can debate the syntax. I won't, since even while I have similar reservations, that will lead to the usual Delphi sucks debate, possible implementation of an-orphaned-at-birth FPC specific syntax, and in the end the Delphi syntax always prevails, leading to a lot of wasted time in discussion and implementation of own inventions.
That is such a common pattern on these lists, I'm thinking about an acronym for it to save time :-) So sufficient to say, I think own syntax inventions are worse than the problem in the first place, and sooner or later we have to live with it.
However there was also a questioning of the use(functionality) of anonymous functions, I hope that I have now at least explained a typical use case, so we can put that to rest.
Please note that I didn't question their use, just the syntax :)
Michael.
In our previous episode, said: One can debate the syntax. I won't, since even while I…
[OT]
It's the Let's Screw FPC Guys Life [LSFGL] warrior call of the Borland/CodeGear/Embracadero employees ;)
L.
or Change Lazarus And QUit Emancipating language-Rules (CLAQUER).
:J
L.
[snip] One point is that you could do the above with a local (and named) procedure as…
2011/10/25 :
How would you preserve the context without finding some place somewhere (on the heap) to store the current values of a, b, and c?
The natural alternative to a closure if you don't have them in an OO language is instead of passing a closure you pass an object (this pattern is called Functor). The object contains the function along with some state. Of course in a static language this involves a lot of boiler plate to define the needed classes with their methods (one class definition for every different closure) but once you have done this you can use it like the closure in the above example and its usage is totally readable:
targetthread.queue(TMyFunctor.Create(targetobject, a, b, c));In our previous episode, said: I hinted on it in earlier procedures, but here a typical…
2011/10/25 Marco van de Voort :
shouldn't this be
targethread.queue(
procedure
begin
targetobject.destinationprocedure(a,b,c);
end;without any parameters since all these variables are captured from the current scope into the closure? The other thread should not need to know anything about them to call it.
In our previous episode, Bernd said:
Afaik you are right. Delphi also allowed the other form, but I thought the syntax would force immediately evaluation of the parameters (and thus only the parameters be stored in case any of a ,b or c are expressions, not all parts of the expressions).
But indeed then the other side also has to call it with parameters, and in this example that defeats the purpose.
2011/10/25 : How would you preserve the context without finding some place somewhere (on…
05.11.2011 22:42, Bernd пишет:
But modern trend is to add closures into OO languages, because code become more laconic.
2011/10/25 : How would you preserve the context without finding some place somewhere (on…
Procedure SomeOuter;
Var
d,e,f : SomeType;
Procedure SomeInner(targetobject:ttargetobject;a:integer;b:someobject;c:string)
begin
targetobject.destinationprocedure(a,b,c);
end;
begin
Targethread.queue(@SomeInner(aobject,d,e,f));
end;No difference with 'closure', except more readable.
Michael.
06.11.2011 1:46, Michael Van Canneyt пишет:
Closures can be returned as a function result but nested procedure not (more strictly, this can be complied but will not work because of lifetime of nested procedure).
Procedure SomeOuter; Var d,e,f : SomeType; Procedure…
2011/11/5 Michael Van Canneyt :
I doubt that this would even compile. Also As I pointed out already the example was wrong, the procedure does not have any arguments, the closure must be "closed over" these variables.
and this:
begin
Targethread.queue(@SomeInner);
end;would compile but it would just pass the procedure variable. This is not a closure. How is the other thread supposed to know the values of the variables that existed only in the scope of SomeOuter?
A closure would be something like this:
Procedure SomeOuter;
Var
d,e,f : SomeType;
Procedure SomeInner
begin
targetobject.destinationprocedure(a,b,c);
end;
begin
Targethread.queue(SomeInner);
end;The compiler would need to create an object on the heap containing the procedure *along* with the needed variables a,b,c and then pass the entire object. The receiving side could then call this method and it would still have access to these variables.
A closure has enclosed variables from the surrounding scope where it was created, hence the name 'closure'. You cannot do this with a procedure variable alone, you need an object on the heap to contain the enclosed variables. The Delphi compiler will behind the scenes create a reference counted object with an 'invoke' method (the procedure SomeInner) and all its needed variables.
It is basically a syntactic shortcut to explicitly defining this class, and creating an instance of it.
I understand all that. That's not the issue.
I didn't mean to say that my example will work with the compiler NOW. Obviously, it would need some extension of the compiler to implement closures.
The only thing I am arguing is that the syntax could have been more clear. Definining a function inside code (or as an argument to another function) is just not Pascal; It goes against everything Pascal stands for.
You could perfectly explicitly declare the closure function outside the code block it is used in, as long as it is AFTER the variables it would need from the outer scope. That is what I wanted to show with my snippet of code. Probably you'd need some kind of extra keyword to distinguish it from 'normal' nested functions.
I am not against closure functionality, although I highly doubt it is *that* useful as some people make it out to be. Even so, I use it in my Javascript programming.
But in Pascal, I would like to see it implemented in a way that doesn't go against Pascal philosophy. In that regard, I consider the way that Borland/CodeGear/Embarcadero implemented it a monstrosity. It simply hurts the eyes...
Michael.
2011/11/6 Michael Van Canneyt :
I am not against closure functionality, although I highly doubt it is *that* useful as some people make it out to be. Even so, I use it in my Javascript programming.
I'm also not entirely sure about the necessity of closures in OP, but I must admit I am not totally against it. I am somewhat undecided. Since we have objects we can easily port every algorithm that needs closures 1:1 to OP without changing anything, we just have to put a ton of type definition boilerplate in front of it but the algorithm itself will look and work 100% the same. It will just pass objects around instead of closures (and in some simple cases where we don't need to enclose data we can take the shortcut and use a procedure variable).
In Javascript there is no difference between 'object' and 'function', they are the same thing, every function is an object, creating functions and passing them around is a totally normal thing in JS, just as normal as it is in OP to create Instances of classes and pass them around.
But I cannot totally deny that closures in OP would be a cool feature. They are not necessary to do what can already be done but they still would be an extremely cool feature which can increase the expression/noise ratio significantly in some cases if used appropriately.
And I believe eventually they will be implemented in FPC. I have absolutely no doubt.
BTW: Here is a post I found while googling for Delphi examples, he explains the approach they took in Delphi:
http://compilers.iecc.com/comparch/article/09-04-067
06.11.2011 1:46, Michael Van Canneyt пишет: Closures can be returned as a function…
Of course, but what Michael means is: closure support does not require necessarily anonymous proceudures/functions/methods.
It would be probably more clear to write and this more pascalish:
Procedure SomeOuter;
Var
d,e,f : SomeType;
Lambda Procedure
SomeInner(targetobject:ttargetobject;a:integer;b:someobject;c:string)
begin
targetobject.destinationprocedure(a,b,c);
end;
begin
Targethread.queue(@SomeInner(aobject,d,e,f));
end;We don't need lambda expressions after all to implement controll statements like e.g. smalltalk.
06.11.2011 15:53, Florian Klämpfl пишет:
OK, agreed, this is more readable than Delphi syntax. But ...
1) If we implement lamdas is FPC we will have to support Delphi syntax.
2) lambda systax is usually as short as possible, but this is not "pascalish".
Of course, but what Michael means is: closure support does not require necessarily…
2011/11/6 Florian Klämpfl :
Why would this function have an argument list? How would the target thread call it?
06.11.2011 15:53, Florian Klämpfl пишет: OK, agreed, this is more readable than…
Alexander Shishkin wroteOK, agreed, this is more readable than Delphi syntax. But ... 1) If we implement lamdas is FPC we will have to support Delphi syntax.
Hi-jacking, the thread, and again should FPC chase Delphi forever? Their technical decisions are directed mostly by "marketing" needs. Should Open Source mimic that?
Now, FPC has provided support for ObjC interface, and Delphi is using that, so maybe it will (and should) be otherwise - Delphi is to provide syntax support for FPC?
thanks,
Dmitry
P.S. a lot of syntax sugar might cause diabetes.
dmitry boyarintsev wroteHi-jacking, the thread, and again should FPC chase Delphi forever?
If we want to offer compatibility with source code written for Delphi, which does happen to be one of FPC's project goals, then yes, we do have to do that to some extent.
Now, FPC has provided support for ObjC interface, and Delphi is using that,
Delphi is only using it for iOS (because they don't have their own ARM compiler yet). They are using a different way to interface with Objective-C that does not use the FPC syntax with their Mac OS X compiler. In fact, they reportedly do it without extending the language in any way, by basing it on dynamic dispatch similar to COM interfaces. That in itself is a good argument for not adopting FPC's syntax: if you can do something without extending the language, it's almost always the better option.
so maybe it will (and should) be otherwise - Delphi is to provide syntax support for FPC?
What Delphi /should/ do is a useless discussion on the FPC lists. If you insist on doing it anyway, please move it to fpc-other.
Jonas
Hi-jacking, the thread, and again should FPC chase Delphi forever? Their technical…
06.11.2011 18:13, dmitry boyarintsev пишет:
FPC support not their decisions but existing Delphi code. This is the propose of several syntax modes in FPC as I understand. Even if Delphi will eventually support FPC dialect it have to maintain compatibility with current Delphi dialect and also FPC should do so.
Hi-jacking, the thread, and again should FPC chase Delphi forever? Their technical…
You mix here result and goal. If FPC supports new Delphi constructs depends on the fact if somebody provides a patch. No more, no less.
Just as an example: if somebody provides patches to support Extended Pascal, FPC will support Extended Pascal, nobody did so in >15 years. Result: FPC supports no Extended Pascal features.
Am 06.11.2011 15:13, schrieb dmitry boyarintsev: > Hi-jacking, the thread, and again should FPC chase Delphi forever? You mix here result and goal. If FPC supports new Delphi constructs depends on the fact if somebody provides a patch. No more, no less.
I have the same feeling as Dmitry: There must be a time when FPC does not run after Delphi. Why not now? Other changes were rejected too.
Just as an example: if somebody provides patches to support Extended Pascal, FPC will support Extended Pascal, nobody did so in >15 years. Result: FPC supports no Extended Pascal features.
Actually the question is: *If* someone is investing time into something is this a useful investment? Or wouldn't it be be better to invest this time into other things, i.e. bug fixes?
Also, implementing all existing language constructs from all other languages into Pascal makes it a monster that no one can handle anymore. Supporting Delphi code sounds good in the first place but in the end it bloats the language to something completely different than was intended. The reasons for the success of Pascal were simplicity and clarity. But now it going into the opposite direction. Introducing new constructs over and over again does not make a language easier to use, just the opposite.
Someone who starts programming in Pascal today has the same (or even worse) learning curve than for all other languages. That is not good IMO.
Feel free to start a fork and we will see what will make it into trunk.
Other changes were rejected too.
Yes. We reject patches to turn FPC into an OS, a C compiler or a coffee machine. No, wait, I think we would accept the last one.
This is everybody's decision. You decided also to write a lengthy mail instead of submitting a patch to a bug report as well while the patch would be much more usefull in my eyes.
> I have the same feeling as Dmitry: There must be a time when FPC does > not run after Delphi. Why not now? Feel free to start a fork and we will see what will make it into trunk.
Sorry, but I don't know what you are talking about. Isn't it you (and a few others) who decide what becomes part of FPC? It's not a democratic vote, isn't it?
> Other changes were rejected too. Yes. We reject patches to turn FPC into an OS, a C compiler or a coffee machine. No, wait, I think we would accept the last one.
But *you* are deciding this, not?
This is everybody's decision. You decided also to write a lengthy mail instead of submitting a patch to a bug report as well while the patch would be much more usefull in my eyes.
Sorry, I don't know how to submit a patch. Forgive me if I am not on the same knowledge level as you on FPC.
That's exactly what he said: you are free to create a fork (= take the FPC source code and do whatever you want with it), and then the currently active FPC developers are also free to take whichever of your patches they consider useful. What's not possible is that other people dictate what you must do with the FPC source code, just like you can't dictate what other people must do.
I don't know how to submit a patch.
http://wiki.freepascal.org/Creating_A_Patch (it was written for Lazarus, but it works pretty much the same with FPC)
Jonas
Sorry, but I don't know what you are talking about. Isn't it you (and a few others) who…
Will you organize democratic votes in the future on rejected patches?
Remember though, there is something like a consititution:
- FPC is a pascal compiler written in pascal.
- Patches may break old code as little as possible and cause no regressions in the regression tests.
If you don't like this, you should fork FPC. Though we can discuss to change the first sentence into
- FPC is a compiler written in pascal for wirthian languages. But to do so, somebody has really to prove it's commitment over years.
Yes, because nobody did yet volunteer to setup and maintain the structure to organize votes on rejected patches. Probably also because their number is too low.
Read the handbook of your browser how to upload files if a website contains such a field. Then go to the issue report in the bug tracker and upload the patch.
I have the same feeling as Dmitry: There must be a time when FPC does not run after…
Agreed 100%. If someone wants to write Delphi and FPC compatible code this is already possible.
I don't understand why FPC should become a 100% Delphi clone instead the "best general software development environment ever" for the only purpose that Delphi users have a free cross platform alternative without to care about FPC compatibility while writing their Delphi code.
I propose to make a review of current and future FPC language constructs and to classify the constructs into different groups (Pascal kernel, OOP kernel, convenience, syntax sugar, can be replaced by, code bloat, Delphi clone...). Eh.., no, I can't do it my self because I don't know all the newer possibilities and there is another FPC related open source project which needs my attention. ;-)
People who want to write code which is understandable by every Pascal coder can limit their use of constructs to the basic groups. It even will be possible to make a streamlined FPC version later without the bloated elements.
Martin
One reason is to make it easy for FPC users to reuse existing Delphi code that is out there without having to rewrite it in an "FPC- compatible way".
Jonas
Is there a big demand? Examples? Because I write most of the code myself I don't know the market well.
Maybe if FPC clearly states that it will not follow Delphi blindly and defines what Delphi devels must do to be FPC compatible and to have the free multi platform alternative there will be more FPC/Delphi compatible code? Now where Embarcadero uses FPC for iOS development is probably a good moment to do so.
Martin
Indy and Synapse are two I know of, but there are probably many more. I also used FPC/Lazarus to port an architectural simulator developed in our group at the university a long time ago (using Delphi 5 or so) to Mac and Linux. I was relatively easy, even though I had no prior experience with developing GUI applications in Lazarus (and still don't really have, actually, since most things just compiled and worked barring some widgetset bugs).
Maybe if FPC clearly states that it will not follow Delphi blindly
We will not do that. Just like we won't say that we will follow them blindly. What happens depends on what code people write, which patches are submitted and what the quality and impact of those patches is. A lot of Delphi-compatibility features have been added to the compiler in the past year simply because Paul Ishenin cares about that and he generally writes good code and tests. And non-Delphi compatible features such as Objective-Pascal and a JVM backend have been added because I cared about that.
and defines what Delphi devels must do to be FPC compatible and to have the free multi platform alternative there will be more FPC/Delphi compatible code?
In general that means limiting themselves to features of Delphi versions from a couple of years back, and not using Windows-specific code.
Now where Embarcadero uses FPC for iOS development is probably a good moment to do so.
I doubt it, because
a) Embarcadero are working on their own ARM compiler and won't ship FPC anymore with future Delphi versions
b) all example code posted by FPC contains every single line of implementation code between {$ifdef FPC} to make it clear that you may have to rewrite that code in the future (although strangely enough they use {$mode objfpc} instead of {$mode delphi} everywhere in that code)
Jonas
Is there a big demand? Examples? Because I write most of the code myself I don't know the…
I speak only for myself.
This is a component that i'd like to see compiled with fpc
http://code.google.com/p/emballo/
The problems
- generic support: bugs.freepascal.org/view.php?id=20503 . Can be workaround by type casting
- reflection/rtti support to call constructor of a given TClass. Can be work around by registering a function that returns an instance or using AfterConstruction to setup object instead of the constructor directly
BTW: i will take the old version version of emballo and rewrite it in an "FPC compatible way" to get things done in the meantime.
Looking also to http://code.google.com/p/delphi-spring-framework/ and http://code.google.com/p/delphi-orm/
Luiz
So probably there are at least two different expectations into FPC which can't be fulfilled both: "best general purpose software development environment ever" and "100% current Delphi compatibility".
Martin
That's exactly what he said: you are free to create a fork (= take the FPC source code…
That's exactly what he said: you are free to create a fork (= take
the FPC source code and do whatever you want with it), and then the currently active FPC developers are also free to take whichever of your patches they consider useful. What's not possible is that other people dictate what you must do with the FPC source code, just like you can't dictate what other people must do.
This argument is pulled out each time someone suggest things that the main developers don't like. But despite from the work this requires it would result in my own island solution. It cannot be the goal that thousands of people spawn their own Pascal dialect. I don't think that anybody is wanting this. I thought this open source project is about having a *public* Pascal language which can be discussed and argued about. I know that there will be no common sense about each and every topic but it should be possible to say opinions which possibly make others change their mind (or not).
So probably there are at least two different expectations into FPC which can't be…
In our previous episode, Martin Schreiber said:
So probably there are at least two different expectations into FPC which can't be fulfilled both: "best general purpose software development environment ever" and "100% current Delphi compatibility".
That "current" is added by you. FPC strives to do that of course, but never had the illusion it was near enough to claim something like that. Not now, and not in the past.
the FPC source code and do whatever you want with it), and then the currently active FPC…
Jürgen Hestermann wroteJonas Maebe schrieb: > That's exactly what he said: you are free to create a fork (= take the FPC source code and do whatever you want with it), and then the currently active FPC developers are also free to take whichever of your patches they consider useful. What's not possible is that other people dictate what you must do with the FPC source code, just like you can't dictate what other people must do. > This argument is pulled out each time someone suggest things that the main developers don't like. But despite from the work this requires it would result in my own island solution. It cannot be the goal that thousands of people spawn their own Pascal dialect. I don't think that anybody is wanting this. I thought this open source project is about having a *public* Pascal language which can be discussed and argued about. I know that there will be no common sense about each and every topic but it should be possible to say opinions which possibly make others change their mind (or not).
The problem is that the work needs to be done. And once it is done, it needs to be maintained, and must impact other potential work as little as possible. Because of these reasons a) people who implement stuff have way more influence than people who only voice their opinion about what/how something should be implemented b) people who have already implemented lots of stuff have more influence than people who have not done that
It's not that longtime developers won't listen to other opinions, but they do have the final say. Without such a dynamic, the project simply cease to exist. After all, without the people who do the work there is nothing at all, not even a project going into a direction that you don't like.
The reason that this argument is always used is simply because that is simply how it is. You can argue that it should be different, but really the only way to do that is to do the work yourself. That may well be an uphill battle if you wish to fundamentally change some things or the development direction of an entire project, in which case starting your own project may be the best option. After all, that would give you the opportunity to demonstrate that your way is actually better and will attract more/better/whatever developers and users, or otherwise will result in something more useful, rather than just arguing that this will be the case and that people should understand that.
Jonas
>> That's exactly what he said: you are free to create a fork > This argument is pulled out each time someone suggest things that
the main developers don't like.
The reason that this argument is always used is simply because that
is simply how it is.
I know that. But still: Why is this argument used like a knee-jerk reaction as soon as someone writes unliked opinions? That's like saying: "Stop critisizing me. I don't like this. I am the boss!". If you don't like to write facts/reasons then don't say anything but using your thought-terminating cliché over and over again just makes you sound arrogant.
It's not that longtime developers won't listen to other opinions,
But that's what you do when using your standard argument.
In our previous episode, Martin Schreiber said: That "current" is added by you. FPC…
Marco van de Voort wroteThat "current" is added by you. FPC strives to do that of course, but never had the illusion it was near enough to claim something like that. Not now, and not in the past.
So what exactly is the goals of FPC then? And please don't tell me "delphi compatible" because then you need to tell me which version of Delphi - and I doubt you can.
As a core developer of FPC can yo please summarize in one or two sentences the actual goal of FPC - that way we are all on the same page.
the main developers don't like. is simply how it is. I know that. But still: Why is this…
The opinion is not unliked but just useless and wastes the time of people who try to use this mailing list to support others using fpc. If you want to express opinions again and again without any consequences like coming up with code just write a blog. You know, "talk is cheap, show me the code" (Thorvalds).
So what exactly is the goals of FPC then? And please don't tell me "delphi compatible"…
Let me answer:
Writing an (L)GPL'ed pascal (*) compiler being self hosting.
(*) pascal might be replaced by 'wirthian languages' if someone with a
lot of commitment over years pops up and works on this.Florian Klaempfl wroteLet me answer: Writing an (L)GPL'ed pascal (*) compiler being self hosting.
From the man himself. OK good, so now we all know the goal is not one
of "delphi compatible" (that is rather limited only as a side effect - nice to have), so please all core developers, stop using that as an excuse to stop other FPC innovation. Over the years I have heard many features being declined because they will "not be delphi compatible".
Examples?
Tomas
of "delphi compatible" (that is rather limited only as a side effect - nice to have), so…
I fear the opposite: all Delphi "crap" will be implemented.
Martin
Examples? Tomas
2011/11/8 Tomas Hajny :
Examples?
I can list them all, but I'm not going to waist my time on them again. Search the mailing list or Mantis.
But to humour you, here is just one of many examples: THelpEvent in the RTL. I proposed a patch to change it to be more in line with FPC's goals [being a cross-platform compiler, so requires cross-platform solutions]. The change was declined because THelpEvent is a direct copy of Delphi's equivalent, and even worse, is very Windows specific in its signature. Yes, it's a small and stupid example, but there are many more like this. Delphi-compatibility seems to trump everything else (as Martin said).
I fear the opposite: all Delphi "crap" will be implemented. Martin
In our previous episode, Martin Schreiber said:
Don't worry, there is also room for FPC "crap" ("case string of" e.g.) :-)
2011/11/8 Tomas Hajny : I can list them all, but I'm not going to waist my time on them…
This is a nice example of my reason for asking. What you list here is not a new feature but change to something what was created in order to provide Delphi compatibility in the first place. Extending such stuff should be possible (and has been done many times), changing it by breaking the compatibility is not necessarily such a good idea.
On the other hand, I don't think that new features are being rejected because they may add something not available in Delphi (FPC already provides features not available in Delphi and there is no reason why more of them shouldn't be added - if they are reasonable and there are people willing to implement and maintain them.
Tomas
2011/11/8 Tomas Hajny : I can list them all, but I'm not going to waist my time on them…
So you wanted to break existing stuff other people probably used? It is indeed one of FPC's policy to avoid breakage of exisiting code.
Or did you propose a TFPHelpEvent?
In our previous episode, Martin Schreiber said: Don't worry, there is also room for FPC…
Which I like but not use because of Delphi 7 compatibility. :-)
Martin
So you wanted to break existing stuff other people probably used? It is indeed one of…
Florian Klaempfl wroteSo you wanted to break existing stuff other people probably used? It is indeed one of FPC's policy to avoid breakage of exisiting code.
Break what existing code? I searched all of FPC, Lazarus, Lazarus CCR and MSEgui - there was no existing usage of THelpEvent. Lazarus's LCL implements there own version of this. So I really didn't see an issue in changing it in FPC. If you (or Marco - the one that declined my proposal the first time round) have an example where it would break existing code, I would love to know about those please.
Now if you want to go down the "delphi compatibility" route, well then FPC is in the wrong anyway! Neither Delphi, nor Kylix has THelpEvent defined in the Classes unit, but rather in the Forms.pas unit. So what delphi is FPC really trying to be compatible with in this case?
Or did you propose a TFPHelpEvent?
I can't remember the details, but I think I proposed that too. In the end, I simply defined what I needed in fpGUI itself. Clearly the latter is the path of least resistance (Martin should agree with his experiences of MSEgui) - though I do prefer to use existing classes from FPC (as a first option).
As I said, in the end I defined what I needed in fpGUI itself, using existing types in the signature, like THelpType and THelpContext - which ARE both defined in the RTL, doesn't reek of Windows'ism.
TfpgHelpEvent = function(AHelpType: THelpType; AHelpContext: THelpContext;
const AHelpKeyword: String; const AHelpFile: String;
var AHandled: Boolean): Boolean of object;For such applications one uses procedure variables in pascal. I still don't see why this…
Florian Klämpfl wrote
Sorry for resurrecting al thread, but p[erhaps better to keep things together.
1) "anonymous methods" in Delphi are made in very Pascalish way, a lot of wording, a lot of boilerplate.
That adds to readability, but makes their use much harder. If you have relatively complex 4-5 lines function, then the overhead is slightly noticeable. But such functions are a borderline to me, having them anonymous hampers both ease of read and ease of debug. I know C++ fans how say that begin/end are awfully long. Well, Delphi style of anonymous functions would frighten them even more.
Here we was devised in 1949 to look like Classic
monumental style building, or at least some "manufacturing plant" style building made of bricks industrial way.
Functional style is like more like elegant houses made of paper and thin plywood, something mayeb of Gothic or Japanese style, easily constructible (composable) to any form you like.
They really are hard to make together. You can read about Nemerle and Scala though, about the attempts.
For example in C++ lambdas look total strangers by syntax, but that is inevitable. When you have to type 20 chars of boilerplate for 3 char function "x+y" - that is too much.
http://www.cprogramming.com/c++11/c++11-lambda-closures.html
However, other than that i like syntax for C++ lambda's. It is clearly distinct for compiler, it separates and thus clearly defines captured values, it is rather laconic.
2) however to treat "x+y" as a proper function definition one should have 2.1) either typeless (at compile type, in runtime that may be dynamical typing, duck typing, whatever) language like LISP or Erlang or Python even generic function
2.2) or strongly typed language with very sophisticated type infering like Nemerle and Scala
"x + y" is a function, but the compiler should look at the context and make guess what would be the types for x, y and result (latter would usually be least common type for x and y);
So compiler looks at the context and turns - where appropriate - "x + y" into
a generic "function<TX, TY, TRes> (const x:TX; const y:TY): TRes; begin Result := x+y; end; "
Quite a lot to generate of three symbols.
Well, there are even more concise syntaxes, using jokers or omissions. For example in collection.filter operations the Predicate is expected (it is called collection.Where in Spring4Delphi and MS.Net). So then "_ > 2" or "> 2" would be correct function, implicated to
a generic "function<SomeContextDependantNumericType> function( const value: SCDNT); begin Result := value>2; end;
It would also be nice for compiler to make some merges.
Surely all that cherries can not be gathered without heavy language and compiler reworking.
Delphi tried to get at least some of those, but 1949 legacy feels there. The question is about possible compromise.
(**** Side note: type inferring is also very useful in Generics. ***)
Some very tiny part of it is even implemented in Delphi :-)Consider { Chu Jetcheng, 2008-07-24 }
http://wiki.freepascal.org/Generics_proposals
var
Obj1: TGeneric of Integer, Real;
begin
Obj1 := TGeneric.Create(32, 3.14);This is quite un-orthodox proposal At the statement, a compiler know the type of Obj1, but does not know the type of TGeneric<X,Y>. Since usually rvalue is parsed with no look at lvalue, such inferring is hardly possible at all. More traditional way would be like
var
Obj1;
begin
Obj1 := TGeneric<String, Integer>.Create(32, 3.14);Where compiler "infers" type of Obj1 looking at the type of value used for assignment.
It is even better if type would be something like
TEvent<String, Record<Field1, Filed2, Array<Items>>>. You may say - make an alias.
Type MyEventHere = TEvent<String, Record<Field1, Filed2, Array<Items>>>.
Sometimes that works, for larger code blocks.
But if you have to declare type for every procedure in your unit, that becomes a mess...
However that is well in the spirit of Wirth.
In 1949 AFAIR you could not have var x: array[0..10] of integer; You should have pre-defined named alias for that array.
And "open arrays" functions parameters of Turbo Pascal 7 would be just a schism and herecy for original Pascal specs.
But we now even have and enjoy dynamic arrays and generalyl do not consider them large enough to have their own dedicated explicitly declared name.
(**** End of Side note. ***)3) Why that matters ?
You can refactor program with more ease.
Imagine you just want to save some table to... XML file. Or write it to string. Or maybe pass it to some processor, that would check its sanity.
What is the table ? Maybe it is dynamic "array of record ..... end;" ? Or maybe it is TDataSet ? Or maybe it is TStringList.Rows ? Or any of that and who knows what else ?
// that is not that spectacular. TDataSet internals are scarcely documented spaghetti. When soem in-memory dataset no more compiles in newer Delphi you'd want to change it to dynamic array or TList, but that would ask to re-write all the units using it! You would end up using TClientDataSet and all its TField objects just to pass dynamic array to make a single iteration over it and dispose. Okay, in the world of many-GHz many-core CPUs that does not matter. But "while not q.eof do begin ... q.next; end;" loop is a bit fragile and redundant in wording. //
Okay, you also want to filter it. Your user wants to see customers with most sales.
So he enters a number and only wants to see those whose sales are above.
AFAIR TDataSet had some filtering event (or was it TBDEDataSet), array does not and should be copied.
The logic is very different for same purpose again, depending on source data type style.
But what if there then be one more filtering wished ? Or what if consumer program needs to apply its internal filtering as well ?
In hypothetical 100% inferring functional style it could look like
procedure Button1OnClick(...);
var Consumer; Data;
begin
Data := CurrentConsumersCollection;
// array, file object, TDataSet - whatever
Consumer := ConsumerArray[RadioGroup1.ItemIndex];
// Save to XML, save to network, show on screen - whatever
if CheckBox1.checked then
Data := Data.Filter( _.total > StrToInt(editSalesThreshhold.Text );
if CheckBox2.checked then
Data := Data.Filter( _.CityCode = StrToInt(editCityCode.Text );
.....
Data.Map(Consumer.StepMethod);
(* or Consumer.Process(Data) *)
end;This function could potentially work with ANY kind of input data containers.
4) And here we come to "capturing" - why those so called "anonymous methods" are better called "closures", why that C++ \starts lambdas not with "()" par but with two pairs "[] ()".
What is the argument type of
" Data := Data.Filter( _.CityCode = StrToInt(editCityCode.Text ); " ?Obviously it only can be a predicate: function<our-data-record-type> (const value:ODRT): boolean;
Otherwise collection should have some fore-knowledge how it would be used later.
Alternatively, it can also have "pointer" second argument, sending all type checking to sewer.
Just how non-Generic TList is practically done. Brr...
Ahem, but how would it get city code to compare ?
We cannot compile 1000 functions with all the reference values of CityCode. So the function should "capture" value of "StrToInt(editCityCode.Text" from calling place.
In OOP language terms that means we create some object where "StrToInt(editCityCode.Text" is some private field. It is exactly how that is implemented in Delphi - via TInterfacedObject with refcounting.
Compilers sees that the auto-generated function should have StrToInt(editCityCode.Text ) as a parameter from external context. It also knows it is not allowed to have due to argument type of Collection.Filter method being single-argument predicate.
So it behind the hood creates that object with extra parameter like private field.
Other possible approaches ? Well, that FPC wiki page mentions Extended Pascal / GNU Pascal "scheme types", tapes tagged with constant values. That maybe could be extended to be var-tagged.
Then there can be hypothetical "function(code:integer) CompareCityCode(const r: record): boolean" type. If it can somehow be considered derived (okay, assignment-compatible) from mere "function CompareCityCode(...):..." then that would be the same idea mostly.
Most hardcore feature would probably be "partial application", i mentioned Scala but even it has it with limitations.
Imagine we have
function CompareCityCode(const value: our-data-record; const referenceCode:
integer): boolean;
begin Result := value.CityCode = referenceCode; end;What would be result of "CompareCityCode(?, 10)" ? It could be a predicate, it could be new boolean function, having single argument "value" and always comparing with 10.
In VM-based languages like Lisp or Java/.Net that can indeed be implemented as function generator.
In native languages that probably can only be implemented as a hidden object with "10" stored to that private field again.
Why bother ? Well, just imagining how much code and how many functions and names would have be written to implement that spectacular Button1Click with its adapting to different datasources, different consumers, different lists of filters on different conditions, etc.
And then one future day this code - now split to many many dependent procedures and types - have to be reworked.
5) It is hard to implement all that laconic fluid features in "heavy industrial" style language of 1949.
Probably would never happen to Pascal. But some parts, some ideas probably can be implemented still.
For example in Delphi one can not do generic function "x+y" except is both "x" and "y" are classes.
But if they are integers or floats - then compiler cannot make a difference, less so infer the types.
Well, x+y is maybe nonsense, but what about Max(x,y), if it could be implemented generically for any type in single place... Well, again i am passing from lambdas to generics - but their practical use is entangled heavily...
Surely 1949-styled Pascal can not make all that features 1st citizens. The question is how much and in what style of compromise can be implemented. Generics were also heresy for original Pascal. But they are implemented, some in Delphi and to some seemingly less extent in FPC as well.
While i pity divergence of syntaxes between Delphi and FPC generics, i strangle would not pity if FPc finally implement
lambdas/closures/anonymous-methods in non-Delphi style. Since Delphi style is so Pascalish, that it heavily limits their practical use.
I'm curious: where do you get this 1948 date from? I'm not even sure that assemblers (as we know them) existed in 1949...
Florian Klämpfl wrote Sorry for resurrecting al thread, but p[erhaps better to keep…
"Arioch" wroteSurely 1949-styled Pascal can not make all that features 1st citizens. The question is how much and in what style of compromise can be
implemented.
I don't know whether you tested recent versions of FPC, but since 2.6.0 the support for Delphi compatible generics improved, though generic functions/methods and constraints are still missing.
Regards,
Sven
Florian Klämpfl wrote Sorry for resurrecting al thread, but p[erhaps better to keep…
I don't think anonymous functions should be added to the are IMHO a negation of what pascal stands for. If your programming style is so strange that you need lamba functions or anonymous functions, then Pascal is simply not for you.
Michael.
+1
I think a lot of people need to get back to program in Pascal...
Ralf
I'm curious: where do you get this 1948 date from? I'm not even sure that assemblers (as…
I'm curious: where do you get this 1948 date from? I'm not even sure that assemblers (as we know them) existed in 1949... Mark Morgan Lloyd
Damn! you're definitely right.
At vwery very least Pascal could not be before Algol-68, which could not be before... ahem.
But now I wonder myself....
????....
Here, found it at last!!!!
look at the picture.
I scanned the 1st number looked like year and it just imprinted without any doubt.
I remember i was slightly surprised like "so early? such a mighty man!" but just imprinted the number and passed by.
I was deep into another theme and year was not important to me, so i just scanned it, noted and went one without single though about possibility.
After all computaiton basis like Turing Machine and Lambda Calculus were developed somewhere around those years. At the moment it did seemes unbelievable but not impossible.
Really, i embarassed myself, thanks for pointing it.
+1 I think a lot of people need to get back to program in Pascal... Ralf
+1 - anonymous functions demonstrate a laziness to software design: what you can't name you actually don't design...
----- Mail original -----
De: "Ralf A. Quint"
À: "FPC-Pascal users discussions"
Envoyé: Jeudi 30 Août 2012 09:26:27
Objet: Re: [fpc-pascal] Re: Delphi's anonymous functions in Free Pascal
+1
I think a lot of people need to get back to program in Pascal...
Ralf
+1 I think a lot of people need to get back to program in Pascal... Ralf
Ralf A. Quint wrote
Well, the same should be told about everything modern pascal is.
Open and dynamic arrays, pointer math, objects, generics, even units. It was all breaking the initial Pascal strictness and rigidness.
Because what was counted "large blocks" deserving their own explicit naming back then - now seems trivial small detail.
Generics are alien to Pascal no more no less than closures.
implemented. I don't know whether you tested recent versions of FPC, but since 2.6.0 the…
Sven Barth-2 wrote
Thanks. No, i just checked wiki and docs and referenced mailing lists letters. Last time i worked with Lazarus were times of Linux transition from 2.4 to 2.6. Don't recall exactly but that was ooold times :-)
Personally i think that introducing yet more keywords is not good thing, when can be avoided.
But since it was done, i did not think that FPC would both implement their native syntax with generics/specialize keywords and keywordless Delphi style.
Lack of generic methods and corresponded partially to it lack of modern RTTI is pity, but hopefully would be resolved.
PS. Checking available docs, besides, was how i came to the topic and was wondered that no one answered why closures matter.
It is surely personal test to like or dislike them. I already said that they can make code hardly readable and hardly debugable is over-used.
And that Delphi model of them makes them impractical for oneliners (where their true power lies) and only practical for complex routines (where they are problematic)
Howeveri wished that their benefits at least were outlined in the thread, referenced from wiki.
Ralf A. Quint wrote Well, the same should be told about everything modern pascal is. Open…
I beg to differ. Read Niklaus' work on why he created Pascal: two objectives stand out : readability and ease-of-compiling. He wrote explicitly he wanted a language he could easily write his compiler in...
Sorry rigidity is not part of the original Pascal mandate. Look at Modula and the more recent Active Oberon language, you'll see objects are not in contradiction with those goals that Niklaus had. Units neither. Generics neither. Pointer (typed) neither.
Anonymous functions (or anonymous whatever) is another debate: as i wrote previously, if you can't name it, you can't design it... Pascal is all about good design, visible in the code, readable. 90% of the time a developer reads code, usually somebody else's. This is a well-known statistic. If Pascal optimizes my reading time, I'm all for it! If the new features conform to the readability and ease-of-compiling principles, then go for it! We shouldn't dwell on the Pascal of the early 1970's. I'm fed up of seeing comparisons of 2012 C++ with 1970 Pascal...
Keep up the good work, fpc team!
Best regards,
Thierry
----- Mail original -----
De: "Arioch"
À:
Envoyé: Jeudi 30 Août 2012 10:04:08
Objet: [fpc-pascal] Re: Delphi's anonymous functions in Free Pascal
Ralf A. Quint wrote
Well, the same should be told about everything modern pascal is.
Open and dynamic arrays, pointer math, objects, generics, even units. It was all breaking the initial Pascal strictness and rigidness.
Because what was counted "large blocks" deserving their own explicit naming back then - now seems trivial small detail.
Generics are alien to Pascal no more no less than closures.
+1 - anonymous functions demonstrate a laziness to software design: what you can't name…
tcoq wrote
a laziness to software design: what you can't name you actually don't design...
Guess you meant "don't want to" instead of "can't" And You mean all the non-named arrays, don't you.
"var x: array[0..10] of integer; " is not only violating Pascal Report, but also is twice lazy.
since one should name every part of design one should type like
type
SomeEnumSemanticName = 0..10;
SomeEnumMapSemanticName = array[SomeEnumSemanticName] of integer;
var x: SomeEnumMapSemanticName;That has a point, for self-documenting if nothing else. But i don't believe it is practically that pervasive as your stated maxima would assume.
Ralf A. Quint wrote Well, the same should be told about everything modern pascal is. Open…
Only pointer math breaks rigidness. The others do not, they enhance it.
Pascal is about readable, clearly structured, strongly typed code.
Exactly. If it had been up to me, they would not have been included either.
Till now, I've seen only 1 actual use of generics in general component code, which kind of supports my theory that the only thing they are useful for is to create a list and collection kind of classes that do not need typecasts. which I think is too little justification, because that could have been achieved differently IMHO.
I started to use lambda functions in Javascript, where they are ubiquitous. Except for some trivial cases, I ended up naming them anyway, so they could be reused.
I just don't see enough justification for them, given that Pascal offers enough other structures to achieve the same effect.
Not every conceivable use case justifies a new language feature. Especially such an abomination as lambda functions, which totally destroys readability.
Michael.
tcoq wrote Guess you meant "don't want to" instead of "can't" And You mean all the…
No, "can't" is the correct word. In Pascal, one should have the ability to name the constructs one uses. For example, i like very much the ability to name my own Event types: "type TOnMyEvent = procedure(aStr: string) of object;". Or my Exception types. Thinking about the event name usually helps me to nail my design.
And you're right, your example is spot on. I use Pascal Analyzer (thanks Peganza!) to check my own programming (as I'm lazy as everybody else), and it detects bad design just like the example you mention. Usually because of the unnamed constant. When I have some time for refactoring, i try removing some of the more offending smells... What's nice about Pascal is that we all smell them easily... ;-)
Thierry
----- Mail original -----
De: "Arioch"
À:
Envoyé: Jeudi 30 Août 2012 10:18:31
Objet: [fpc-pascal] Re: Delphi's anonymous functions in Free Pascal
tcoq wrote
a laziness to software design: what you can't name you actually don't design...
Guess you meant "don't want to" instead of "can't" And You mean all the non-named arrays, don't you.
"var x: array[0..10] of integer; " is not only violating Pascal Report, but also is twice lazy.
since one should name every part of design one should type like
type
SomeEnumSemanticName = 0..10;
SomeEnumMapSemanticName = array[SomeEnumSemanticName] of integer;
var x: SomeEnumMapSemanticName;That has a point, for self-documenting if nothing else. But i don't believe it is practically that pervasive as your stated maxima would assume.
tcoq wrote Guess you meant "don't want to" instead of "can't" And You mean all the…
Except that not defining a distinct type emphasises that the array is only being declared once, and is not being passed around as a parameter. So I'd suggest that there are cases where the first example is appropriate, except obviously that that ..10 is rarely if ever acceptable.
I beg to differ. Read Niklaus' work on why he created Pascal: two objectives stand out :…
If the new features conform to the readability
That heavily depends upon which patterns are known to reader. We all are patterns recognizers.
And today world is very different.
In my example sketch, the calling like "Data.Filter( _.TotalSale > 20 )" is concise and easy to understand.
Okay, given your heavy Pascal background you would stumble because you would see the thing between bracket as an unbelievable heresy. For people without Pascal background that would be easy to read.
At least easier than scrolling into 3 different functions probably belonging to different objects that would implement the same idea in traditional imperative way.
Generics are the ease of reading ? i saw a lot of posts calling Boost and "Modern C++ Programming" nothing else than perversion. And the enigma of generics-related compiling error messages are but a common point.
But surely remembering single TList<T> is easier than remembering dozen of specialized TLists.
It is all about scale and experience.
And we are now recognizing larger blocks of code, than in seventies. Atoms are larger today.
Can closures be abused ? Easily. Can generics be abused ? easily. Can pointers be abused? For sure.
Strings ? After i saw the tutorial(sic!) on database access, that compared word (two bytes) values via "IntToHex(value, 2) = string-constant" i am sure they easily can.
When you think about ease to read i believe you should compare to values.
* How easier would be code to read when the feature used properly ?
* How harder code would be to read when the feature is misused ?
Frankly, i don't know what weights should those values have, but i tend to believe 1st is more important. You can always make spaghetti copy-pasted code with anything.
5 lines anonymous functions are hard to debug and separate from surrounding code.
10 lines ones would be nightmare.
1-2 liners are heavily simplifying reading, where they can be applied.
and ease-of-compiling principles
Generics are one more indirection layer for compiler to care about. They are not simplifying compiling.
And they make dynamic modules like Delphi BPLs no more self-contained.
Objects are not easying compiler - now compiler should care about hidden Self parameter and generate different code for seemingly the same function, if it is method or detached function.
And i did not mentioned viortual methods and properties yet. Ref-counted interfaces are even more burden.
Dynamic arrays and strings are not easying compilation - they require a lot of hidden "compiler magic" in each statement using them.
Supporting multiple platforms, supporting multiple Pascal extensions - it all has its price making compilation more complex.
Easy compiling is good goal in the row of other ones. It has its weight but it is quite far from absolute.
-----
This is funny to remember today. ;-)
When i run BP 7 on 80286 computers, and then compared with size and speed of TP 5.5 - i was sure as hell that OOP is for lazy programmers, who cannot make code fast and small.
And i remember comparing speed of Virtual Pascal and contemporary FPC. VP bet everything on compilation efficiency. And died.
But afterall i am quitting on that. Since FPC are lacking closures i am sure here are mostly people who personally dislike them. I wanted to document why closures are good and do matter. Hopefully i did it to the extent i was able to. Surely i would not be able to convince you infinite time. So the rest of arguments would be questions of personal tastes and it would bring nothing but flamewar.
Everything is compromise, with it bright and dark sides. And everything has its personal bets in every compromise.
Allow me to congratulate you all with Lazarus 1.0 release and thank you with good and practical language implementation.
Have a nice TimeOfDay();*)
Ralf A. Quint wrote Well, the same should be told about everything modern pascal is. Open…
You seem to be very rigid over your view of Pascal yourself. With everything you quoted above (but pointer math) Pascal is not a toy language any more; unfortunately many recall it as such and keep pondering about the P language...
(hey, I first had programming classes in middle school on TP6.0 when the strongest machine in computer class was a 386SX 16MHz; that the teacher had, we banged on 286...
we had some intro to (Borland) C(++) later on,
but after Pascal, C seemed so obfuscated, I gave up on it and only write small C programs for microcontrollers where it is as rigid as Pascal :J )
MvC has a point in saying 'pointer math is what spoils it' - pointer math is itself a 'feature' dragged into C++ from 'c', the verbose assembler :J
L.
Except that not defining a distinct type emphasises that the array is only being declared…
Same for closures, exactly.
The function is represent some primitive action or criteria that is not worth re-using and clattering namespace in both compiler and developer.
More so, i believe that holds for all named/non-named entities. Be it array, value, function of if/while condition, etc
The thing that is not named is small, with narrow use span, and is expected to be recognized and read by human as some kind of "reading atom" The thing named is more about architecture and documentation.
and is not being passed around as a parameter.
Be that the case - there would be no Open Array parameters. //well, i just want to say my opinion here. I frankly don't want arguing yet another topic //
So I'd suggest that there are cases where the first example is appropriate, except obviously that that ..10 is rarely if ever acceptable.
if 10 is unacceptable then so is 0.
one should rather explicitly name type for (0..10) rather than two constants for 0 and for 10.
You seem to be very rigid over your view of Pascal yourself. With everything you quoted…
Pascal never was a toy language. It always have too much required naming-and-declarations/boilerplate/obstacles/you-name-it
Basic, Logo - let them be. But not the Pascal.
It was educational language but it was damn serious educational language.
However i believe that your "but pointer math" is only a matter of habit.
Function pointers, virtual methods, interfaces - they all mean when you see function call you don't know which function is actually called.
You think of them as easing the reading only because you got used to them. You mastered those concepts and recognition patterns. Show that code to old school Classic Basic programmer, and he would flee in awe.
For a long time i sticked to Delphi 5 and did not see any benefit to upgrade, so i understand programming in classic ObjectPascal. But call me spoiled, I finally switched to XE2 and generics and closures do simplify code. But of course when and after you make them patterns you recognize at 1st glance. So, habits.
Well, finally good bye. :-)
That heavily depends upon which patterns are known to reader. We all are patterns…
Arioch wrote> If the new features conform to the readability
[snip]
Regarding this: I wish to stress that my views on lambdas or closures are my own;Other people on the compiler team may have different ideas, so maybe they will make it into the compiler. Just like Generics did, or advanced records and some other weird Delphi things of which I totally do not see the use :)
But - and I think the whole compiler team shares this idea - if implemented, it will be in a pascal-ish way, i.e. rather verbose.
Simply because it is Pascal, after all, and not some C derivative language (java, C#, Javascript, PHP, Perl whatnot...)
Michael.
Regarding this: I wish to stress that my views on lambdas or closures are
my own;For what i understand, those are different things. Lambdas are runtime code generators and are out of question for natively compiled language.
Closures are not.
Maybe that is nitpicking today, since the names seems to be substituting each other outside functional languages realm where those concepts were born.
But - and I think the whole compiler team shares this idea - if
implemented,
it will be in a pascal-ish way, i.e. rather verbose.
Well, views for views.
That is Delphi way you describe. Beauty of principles. And that would be harmingly impractical.
Closures are about concise way to express one-liners. If you have to type 30 chars instead of 3 - their use became hard and impractical.
This would suppress using closures for one-liners, where that are useful, safe and enhancing code readability and composability. That would promote their use for complex code chunks where they are dangerous and bad.
From personal experience, when i first time saw how pascalish is closures
implementation in Delphi i just admired the ease in which that concept was fused into the language of very different style built upon very different ideas. It was so elegant when reading docs, i admired it. Like probably you do.
But that next to ruined their use in practice.
That is where i loose my consistency.
I do want Delphi and FPC have shared libraries, which mean i want FPC to support as much Delphi syntax as feasible.
I do want generics in both and hence want FPC support Delphi generics syntax.
I do want closures in both and... and completely cold-hearted if FP would support Delphi syntax of them or not.
While generally i feel kind of disgust at C syntax, i have to admit that their so-called lambdas are ugly but might be practical.
Not really: it breaks my eyes, just as it does in JavaScript :(
Michael.
Pascal never was a toy language. It always have too much required…
Thank you but I am a professional trainer for C++, Java, Ada and other languages including Lisp. I am "used to" those languages. I consistently see young professionals stumble upon those constructs they are "used to". Furthermore, all the professional users of the developed software are not "used to" and cannot read the implementation of the algorithms they have specified. This is possible and feasible in Pascal with great efficiency.
<snip>
You think of them as easing the reading only because you got used to them. You mastered those concepts and recognition patterns. Show that code to old school Classic Basic programmer, and he would flee in awe. <snip>
Not really: it breaks my eyes, just as it does in JavaScript :( Michael.
In our previous episode, said:
This thread is mostly about the semantics and the need.
But what about the implementation? I heard that in Delphi you have to be careful with anonymous methods because it not always catches expressions and variables, and that there are many corner cases?
tcoq wrote Guess you meant "don't want to" instead of "can't" And You mean all the…
Sorry, but that example of yours is who has
learned to program in Pascal should be able write clearly understandable programs, not obfuscate just for 'the heck of it'. But then common sense seems to have turned into a rare commodity these days.
Pascal has evolved since Wirth's original design back in the 70s, nobody is writing serious programs in the original defined language set anymore, I dare to day that even ISO Pascal is not all that useful for real life programs anymore.
A lot of extensions, like units or (objects in general) that you mentioned have been done in a way that still leave the very basics of Pascal intact.
But all the fluff that you (and others) are proposing all the time just aim at completely change the language for no other than self-serving reasons and that's why people rightfully oppose such proposals...
Ralf
I still fail to see where annonymous functions could succeed where functional types (part of pascal since last millenia) wouldnt...
2012/8/30 Ralf A. Quint :
That heavily depends upon which patterns are known to reader. We all are patterns…
The closures (or anonymous functions as they are called in Delphi) are missing, because none of the developers has them on the important slots of the todo lists. So as long as nobody comes and implements them then they are not going to be implemented (at least in the near future). One member of the community stepped up some months ago to implement them (he even has a branch in SVN), but he didn't go far. I don't know whether it was his motivation or his time or his knowledge that left him...
Regards,
Sven
Sorry, but that example of yours is who has learned to program in Pascal should be able…
Ralf A. Quint wrotePascal has evolved since Wirth's original design back in the 70s
This is true. But there are two aspects of the Pascal extensions of the last years (decades) that contradict with what I would call the "spirit of Pascal":
1.) Many "extensions" add to the learning curve of newbies (where will Pascal be in 10 or 20 years and how long does it take a pupil to learn it?). Adding extensions over and over again without much thinking will ruin the language some day because nobody will try this bloated software anymore. I have programmed with Turbo Pascal quite a lot in the 80s and 90s but when I read about the "recently" added concepts I don't understand a word (and I also never missed them!). It seems that these extensions cannot even be easily explained because the concepts are very obscure and require sophisticated knowledge about the compiler to understand them. Extensions in the past were very easy to understand and to handle.
2.) Many "extensions" come from other languages and break fundamental (Pascal) laws (as I would call them). For example, to me an identifier *has* to mean the same in all contexts of a program (whether declaration, function parameter, part of an expression, ..). Dynamic arrays violate this by meaning the address of a pointer or the address of the first array element depending on whether they are dereferenced or not. Pointers should be shown as pointers and not obscured. This leads to a very lot of misunderstandings. Borland should have looked for a cleaner solution for such dynamic arrays IMO. But now the sin has been commited and cannot be withdrawn. Nevertheless, no new sins should be added anymore.
The result is that Pascal is no longer that clear and easy to learn (yet powerful) language that it was. Of course, you can still ignore all the extensions that have been added but you cannot understand foreign code anymore (which is often necessary to understand what happens in the compiler or libraries when using them).
The closures (or anonymous functions as they are called in Delphi) are missing, because…
In our previous episode, Sven Barth said:
Besides that, I've seen some question marks about that feature in the Delphi community too. Specially the predictability of the state that is actually captured by the anonymous function.
That heavily depends upon which patterns are known to reader. We all are patterns…
Hi,
...
This was sad to me. I ported the FPC system libraries (All of sysutils,pas, etc.) to VP with the goal of helping it live longer and work better on linux. The next version of SysUtils for FPC used features VPC didn't have, and I couldn't fake without modifying the compiler. I have the compiler source (The author made a "Core Team" to work on the compiler, and shared the source code and some bata builds for linux, etc.). Unfortunately, at that time I was in college, and didn't have time to learn the intricacies of i386 ASM when I was already dealing with MIPS ASM in school!
The compiler is one solid block of ASM code, and about impossible for anyone but the author to modify, I suspect. It was perhaps the right design decision at the time, however.
I don't think personal taste should come into it. As far as I know, one of the missions of FPC is to be an alternative to other Pascal compilers, which means we should strive for feature parity with the popular distributions. We could go the "Pure" route, but then we would end up with something nearly useless like GPC. (I tried GPC before around year 2000, and I couldn't even compile Hello World type programs from TP7!)
Allow me to congratulate you all with Lazarus 1.0 release and thank you with good and practical language implementation.
Likewise. I wish I had more time to contribute to this great "product".
Have a nice TimeOfDay();*)
Thank you,
Noah Silva
This is true. But there are two aspects of the Pascal extensions of the last years…
Hi,
Perhaps, and I agree with you to some extent. You can pick up Pascal and do something like:
program hello;
begin
writeln('Hello World');
end;hit compile, and watch it run - even now. And that's great, but if you want to write a web browser, or an application server, or a GUI application, you need to do an awful lot of manual work in, f.e. TP7. The first time I saw TurboVision, I thought "What a monster!", what with all those carrots for dereferencing the old style Objects, etc. Yet writing something like the TP7 editor without OOP would have been more a of a chore chan learning TurboVision for sure.
Anyone who says "I just want to save a value in a file" wouldn't want to learn SQL either - but once you have learned SQL, a lot more is possible. Actually, one of the reasons I like Pascal is because you can do low level things and high-level things in the same language. Normally I try to do everything high-level, but sometimes we have to do some dirty-work, and we can when needed. A good example is that LCL and FPC itself is written in Pascal. (Unlike, say, VB6, which is just scripting language for components written in C, really).
2.) Many "extensions" come from other languages and break fundamental (Pascal) laws (as I would call them). For example, to me an identifier *has* to mean the same in all contexts of a program (whether declaration, function parameter, part of an expression, ..). Dynamic arrays violate this by meaning the address of a pointer or the address of the first array element depending on whether they are dereferenced or not. Pointers should be shown as pointers and not obscured. This leads to a very lot of misunderstandings. Borland should have looked for a cleaner solution for such dynamic arrays IMO. But now the sin has been commited and cannot be withdrawn. Nevertheless, no new sins should be added anymore.
Well the extensions usually come because they are useful, and people have demanded them. If you are only using Pascal, then of course, they may seem like unwanted fluff. If you have used those features in other languages and then Pascal doesn't have them, then you would feel very limited. For example, pascal has "With.. Do". I use this all the time like:
With Object1 do
begin
size := 1;
color := green;
width := 84;
Style := stNew;
end;
In other languages I use, I have to laboriously type;
Object1.size = 1;
Object1.color = green;
...But for example, ABAP programmers who have never used pascal have no idea that they are missing this feature. On the other hand, it would be super amazingly convenient if Pascal has the database integration that ABAP has, but most people who use FPC have no idea about this feature, so they don't know what they are missing.
The dynamic arrays thing also applies to LongStrings as well, but you should never have to dereference either in normal circumstances.
The result is that Pascal is no longer that clear and easy to learn (yet powerful) language that it was. Of course, you can still ignore all the extensions that have been added but you cannot understand foreign code anymore (which is often necessary to understand what happens in the compiler or libraries when using them).
Well... Understanding foreign code is difficult either way. For example, though, I think understanding foreign code that uses standard features is easier than understanding old foreign code that fakes those features with older pascal versions that lacked a standard way of implementing the functionality. For example, I have seen:
1. Hand-rolled dynamic array code full of pointer dereferences and malloc() calls.
2. Hand-rolled variant code full of structures with multiple interpretations and typecasting.
3. Hand-rolled generic features, full of typecasting random objects to "Pointer" or "PObject". (This is very common in Delphi code, since StringLists, etc., can hold "Objects").
4. Hand-rolled OOP functionality with VMT in a record.... (Before OOP was introduced into Pascal).
All of these things are easier to understand if there is a common standard that people use, even if you have to learn that standard first. For example, I don't consider myself a Java Guru, but for most basic things, there is one standard way of doing it which everyone uses, and I can look up that library to see what's going on. That's better than trying to figure out a bunch of convoluted code where the program logic is intermixed with the implementation of features that should be in the compiler or (at least) a separate library).
Either way, when you want to do complicated things, you will need to choose between three options
1. Implement the feature manually in code (if possible)
2. Do without the feature and write your program (if possible, may require much more effort)
3. Have the feature implemented into the language, so that everyone can use it, and use it in the same way.
If you are only writing simple programs, though, you can of course ignore the extensions in most cases. I personally ignore a lot of things. I very rarely use Variants, TStream, etc. I also prefer to write and execute SQL statements than to use the OOP database features. On the other hand, some new features I used immediately as they became available because they allow me to do that much less work or stop using TypeCasting (Dynamic Arrays, Long Strings, Generics, etc.)
At any rate, it really comes down to what people want FPC to be:
1. A viable alternative to Delphi and the other compilers and an active language for developers to use.
2. A project to duplicate the antique TP7 compiler on modern hardware for enthusiast programmers.
I am not saying that option 2 is bad, but I think there is a lot of demand for option #1. Personally, if I couldn't do #1 in Pascal, I would be forced to use Java or Mono for writing complex cross-platform software, so I hope FPC keeps on track.
Thank you,
Noah Silva
_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal