Discussion:
[fpc-pascal] Delphi's anonymous functions in Free Pascal
Andrew Pennebaker
2011-10-17 20:53:39 UTC
Permalink
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
Sven Barth
2011-10-18 08:55:11 UTC
Permalink
Post by Andrew Pennebaker
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?
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
Lukasz Sokol
2011-10-18 08:57:53 UTC
Permalink
Post by Andrew Pennebaker
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 <http://www.yellosoft.us>
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.
Lukasz Sokol
2011-10-18 09:27:38 UTC
Permalink
[...]
(facepalm)
I did not try 'anonymous' function as you asked, oh. Need to learn to read ;)

L.
Andrew Pennebaker
2011-10-18 18:10:42 UTC
Permalink
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
Post by Lukasz Sokol
Post by Andrew Pennebaker
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 <http://www.yellosoft.us>
TMyFunction: function(AMyParam : TType): TOtherType;
function MyFunctionWithArbitraryName(AMyParam: TType): TOtherType;
begin
{do something with AMyParam}
end;
//then (or before, if the TMyFunction is in type declaration section)
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.
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Roland Schäfer
2011-10-18 19:27:32 UTC
Permalink
Post by Andrew Pennebaker
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.)
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
Post by Andrew Pennebaker
Maybe you could fork my code
Out of curiosity: Is that the impersonal "you"?
Post by Andrew Pennebaker
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
Post by Andrew Pennebaker
Post by Lukasz Sokol
Post by Andrew Pennebaker
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 <http://www.yellosoft.us>
TMyFunction: function(AMyParam : TType): TOtherType;
function MyFunctionWithArbitraryName(AMyParam: TType): TOtherType;
begin
{do something with AMyParam}
end;
//then (or before, if the TMyFunction is in type declaration section)
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.
Sven Barth
2011-10-18 19:42:22 UTC
Permalink
Post by Roland Schäfer
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).
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
Michael Fuchs
2011-10-19 07:31:58 UTC
Permalink
Post by Sven Barth
For anonymous functions you can take a look at Embarcadero's Delphi help
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
Sven Barth
2011-10-19 08:16:09 UTC
Permalink
Post by Michael Fuchs
I would prefer a style like
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
Michael Fuchs
2011-10-19 08:36:29 UTC
Permalink
Post by Sven Barth
Post by Michael Fuchs
I would prefer a style like
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.
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
Alexander Shishkin
2011-10-19 09:14:34 UTC
Permalink
Post by Sven Barth
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.
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;
end;
Regards,
Sven
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
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;"
leledumbo
2011-10-19 17:07:59 UTC
Permalink
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

--
View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Delphi-s-anonymous-functions-in-Free-Pascal-tp4911527p4918629.html
Sent from the Free Pascal - General mailing list archive at Nabble.com.
Florian Klämpfl
2011-10-19 18:04:08 UTC
Permalink
Post by Sven Barth
Post by Michael Fuchs
I would prefer a style like
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).
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
Andrew Pennebaker
2011-10-19 18:23:56 UTC
Permalink
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
Post by Florian Klämpfl
Post by Sven Barth
Post by Michael Fuchs
I would prefer a style like
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).
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
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Florian Klämpfl
2011-10-19 18:30:11 UTC
Permalink
For such applications one uses procedure variables in pascal.
Post by Andrew Pennebaker
(map f collection)
This is the prototypical way to run a function over each element in a
collection, returning the results.
(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.
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.
Michael Fuchs
2011-10-19 20:32:57 UTC
Permalink
Post by Florian Klämpfl
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.
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
Andrew Pennebaker
2011-10-19 21:28:35 UTC
Permalink
Sven Barth
2011-10-20 06:14:33 UTC
Permalink
Am 19.10.2011 23:28, schrieb Andrew Pennebaker:
Felipe Monteiro de Carvalho
2011-10-20 06:32:43 UTC
Permalink
On Wed, Oct 19, 2011 at 11:28 PM, Andrew Pennebaker
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.
So just make a function instead of a procedure?
--
Felipe Monteiro de Carvalho
Florian Klaempfl
2011-10-20 06:40:51 UTC
Permalink
Am 19.10.2011 23:28, schrieb Andrew Pennebaker:
Arioch
2012-08-29 08:36:48 UTC
Permalink
Post by Florian Klämpfl
Post by Andrew Pennebaker
Post by Andrew Pennebaker
This is the prototypical way to run a function over each element in a
collection, returning the results.
(map (lambda (x) (+ x 1)) '(1 2 3))
-> (2 3 4)
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.
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 are at dilemma. Pascal 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&lt;Field1, Filed2, Array&lt;Items>>>.
You may say - make an alias.
Type MyEventHere = TEvent<String, Record&lt;Field1, Filed2,
Array&lt;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.



--
View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Delphi-s-anonymous-functions-in-Free-Pascal-tp4911527p5711032.html
Sent from the Free Pascal - General mailing list archive at Nabble.com.
Mark Morgan Lloyd
2012-08-29 21:12:52 UTC
Permalink
Post by Arioch
Here we are at dilemma. Pascal 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
(compostable) to any form you like.
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
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]
Sven Barth
2012-08-30 06:37:42 UTC
Permalink
Post by Arioch
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 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
m***@wisa.be
2012-08-30 07:09:49 UTC
Permalink
Post by Arioch
Post by Florian Klämpfl
Post by Andrew Pennebaker
Post by Andrew Pennebaker
This is the prototypical way to run a function over each element in a
collection, returning the results.
(map (lambda (x) (+ x 1)) '(1 2 3))
-> (2 3 4)
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.
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.
I don't think anonymous functions should be added to the compiler at all.

They 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.
Ralf A. Quint
2012-08-30 07:26:27 UTC
Permalink
Post by m***@wisa.be
I don't think anonymous functions should be added to the compiler at all.
They 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

Andrew Pennebaker
2011-10-18 20:23:51 UTC
Permalink
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
Post by Roland Schäfer
Post by Andrew Pennebaker
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
Post by Andrew Pennebaker
any generator function.
E.g., GenArray(GenChar) would return a random string. (Except I don't
know
Post by Andrew Pennebaker
the syntax for passing function pointers.)
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
Post by Andrew Pennebaker
Maybe you could fork my code
Out of curiosity: Is that the impersonal "you"?
Post by Andrew Pennebaker
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
Post by Andrew Pennebaker
Post by Lukasz Sokol
Post by Andrew Pennebaker
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 <http://www.yellosoft.us>
TMyFunction: function(AMyParam : TType): TOtherType;
function MyFunctionWithArbitraryName(AMyParam: TType): TOtherType;
begin
{do something with AMyParam}
end;
//then (or before, if the TMyFunction is in type declaration section)
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 =
Post by Andrew Pennebaker
Post by Lukasz Sokol
({...});
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
Post by Andrew Pennebaker
Post by Lukasz Sokol
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
TMyFunction)
Post by Andrew Pennebaker
Post by Lukasz Sokol
and no other type;
(An obvious workaround to that is to use varargs ;) but I did not try
that
Post by Andrew Pennebaker
Post by Lukasz Sokol
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.
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Roland Schäfer
2011-10-18 21:03:16 UTC
Permalink
Post by Andrew Pennebaker
Schä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.
Post by Andrew Pennebaker
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.
Post by Andrew Pennebaker
but there's only so much you can do without lambdas.
I saw the l-word coming.
Post by Andrew Pennebaker
If I decide to use pointers,
... you'll end up on CodeSOD.
Post by Andrew Pennebaker
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.
Post by Andrew Pennebaker
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
Andrew Pennebaker
2011-10-18 21:26:09 UTC
Permalink
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
Post by Roland Schäfer
Post by Andrew Pennebaker
Schä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.
Post by Andrew Pennebaker
Yes, pointers are probably the only way I can implement this, for now. If
at
Post by Andrew Pennebaker
all possible, I'd like to use more idiomatic Pascal code.
Those sentences form a contradiction.
Post by Andrew Pennebaker
but there's only so much you can do without lambdas.
I saw the l-word coming.
Post by Andrew Pennebaker
If I decide to use pointers,
... you'll end up on CodeSOD.
Post by Andrew Pennebaker
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.
Post by Andrew Pennebaker
In C you have to know the entire function signature and explicitly cast
the pointer
Post by Andrew Pennebaker
to that before you can call it. Does Pascal also require this, or can I
just
Post by Andrew Pennebaker
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
Alberto Narduzzi
2011-10-18 19:41:32 UTC
Permalink
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.
Lukasz Sokol
2011-10-19 08:27:21 UTC
Permalink
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...]
Gregory M. Turner
2011-10-20 19:09:01 UTC
Permalink
----- Original Message -----
Post by Florian Klämpfl
For such applications one uses procedure variables in pascal.
Post by Andrew Pennebaker
(map (lambda (x) (+ x 1)) '(1 2 3))
-> (2 3 4)
[snip!]
Post by Florian Klämpfl
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.
[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:



has all the capabilities of Object Pascal (with less flowery syntactic sugar to mess up the purity of the system).

:P

--
Greg Turner

P.S., hello, list!
Florian Klämpfl
2011-10-20 19:17:31 UTC
Permalink
Post by Gregory M. Turner
Interesting discussion -- at least for me, I didn't know Delphi had this feature.
http://youtu.be/cYw2ewoO6c4
has all the capabilities of Object Pascal (with less flowery syntactic sugar to mess up the purity of the system).
If anybody does not see why increasing complexity without a good reason
should be avoided, I recommend:


Juha Manninen
2011-10-20 20:31:16 UTC
Permalink
Post by Florian Klämpfl
If anybody does not see why increasing complexity without a good reason
http://youtu.be/kYUrqdUyEpI
:-)

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
Florian Klämpfl
2011-10-20 20:55:14 UTC
Permalink
Post by Juha Manninen
They have some very important uses, like making multithreading easier.
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.
Graeme Geldenhuys
2011-10-21 08:03:27 UTC
Permalink
Post by Florian Klämpfl
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
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 -
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/
leledumbo
2011-10-21 15:41:16 UTC
Permalink
Post by Graeme Geldenhuys
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.

--
View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Delphi-s-anonymous-functions-in-Free-Pascal-tp4911527p4925137.html
Sent from the Free Pascal - General mailing list archive at Nabble.com.
waldo kitty
2011-10-21 00:23:11 UTC
Permalink
Post by Florian Klämpfl
Post by Gregory M. Turner
Interesting discussion -- at least for me, I didn't know Delphi had this feature.
http://youtu.be/cYw2ewoO6c4
has all the capabilities of Object Pascal (with less flowery syntactic sugar to mess up the purity of the system).
If anybody does not see why increasing complexity without a good reason
http://youtu.be/kYUrqdUyEpI
+1000000000000~

;)
Andrew Pennebaker
2011-10-21 01:49:15 UTC
Permalink
If anybody does not see why increasing complexity without a good reason
should be avoided, I recommend:

http://youtu.be/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
Post by leledumbo
Post by Gregory M. Turner
Interesting discussion -- at least for me, I didn't know Delphi had this
feature.
Post by Gregory M. Turner
http://youtu.be/cYw2ewoO6c4
has all the capabilities of Object Pascal (with less flowery syntactic
sugar to mess up the purity of the system).
If anybody does not see why increasing complexity without a good reason
http://youtu.be/kYUrqdUyEpI
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Florian Klaempfl
2011-10-21 06:37:32 UTC
Permalink
Lisp 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.
Jürgen Hestermann
2011-10-21 05:25:26 UTC
Permalink
Post by Florian Klämpfl
If anybody does not see why increasing complexity without a good reason
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".
Juha Manninen
2011-10-21 06:59:18 UTC
Permalink
Post by Jürgen Hestermann
Post by Florian Klämpfl
If anybody does not see why increasing complexity without a good reason
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".
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
Jürgen Hestermann
2011-10-21 17:26:02 UTC
Permalink
Post by Juha Manninen
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.
Post by Juha Manninen
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.
Post by Juha Manninen
The challenge is to add only the RIGHT features.
That's true. But now the mark is overshot already.
Post by Juha Manninen
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.
Post by Juha Manninen
Closures seem like a powerful thing which can improve code.
Same as for closures, I don't know them.
Post by Juha Manninen
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.
waldo kitty
2011-10-25 01:23:10 UTC
Permalink
Post by Florian Klämpfl
If anybody does not see why increasing complexity without a good reason
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".
+1 (based on some of the recent stuff being posted :) )
Gregory M. Turner
2011-10-20 19:53:21 UTC
Permalink
----- Original Message -----
Post by Florian Klämpfl
Post by Gregory M. Turner
In case anyone really doesn't see the point, consider that this
http://youtu.be/cYw2ewoO6c4
If anybody does not see why increasing complexity without a good
reason
http://youtu.be/kYUrqdUyEpI
:)

Good point. I guess nothing's O(free lunch).
--
-gmt
Juha Manninen
2011-10-20 20:35:16 UTC
Permalink
Post by 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
waldo kitty
2011-10-21 00:25:24 UTC
Permalink
Post by 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.
i still fight, today, with much of my LISP code... :? :(
Alexander Shishkin
2011-10-21 16:51:41 UTC
Permalink
Post by 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?
Marco van de Voort
2011-10-21 17:46:54 UTC
Permalink
The link below describes two uses for anonymous methods.

http://stackoverflow.com/questions/7818759/delphi-anonymus-methods-pro-and-cons-good-practices-when-using-closuresanony/7821882#comment9576663_7821882

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)
Gregory M. Turner
2011-10-22 02:35:59 UTC
Permalink
----- Original Message -----
Post by Alexander Shishkin
Post by 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?
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
Juha Manninen
2011-10-22 07:57:32 UTC
Permalink
Post by Gregory M. Turner
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.
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
t***@free.fr
2011-10-25 10:42:07 UTC
Permalink
+1
----- Mail Original -----
De: "Graeme Geldenhuys" <***@gmail.com>
À: "FPC-Pascal users discussions" <fpc-***@lists.freepascal.org>
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
Post by Florian Klämpfl
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
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 -
--
fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal
http://fpgui.sourceforge.net/

_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Marco van de Voort
2011-10-25 11:11:05 UTC
Permalink
Post by Graeme Geldenhuys
Post by Florian Klämpfl
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. :)
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 FPC

I 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.
m***@wisa.be
2011-10-25 11:22:03 UTC
Permalink
Post by Marco van de Voort
Post by Graeme Geldenhuys
Post by Florian Klämpfl
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. :)
I hinted on it in earlier procedures, but here a typical anonymous method
usecase.
[snip]
Post by Marco van de Voort
-~-------------------------------
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.
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.
Bernd
2011-11-05 18:42:10 UTC
Permalink
Post by Marco van de Voort
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.
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.
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));
Alexander Shishkin
2011-11-05 19:50:38 UTC
Permalink
Post by Bernd
Post by Marco van de Voort
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.
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.
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
targetthread.queue(TMyFunctor.Create(targetobject, a, b, c));
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
But modern trend is to add closures into OO languages, because code
become more laconic.
Michael Van Canneyt
2011-11-05 21:46:12 UTC
Permalink
Post by Bernd
Post by Marco van de Voort
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.
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.
How would you preserve the context without finding some place
somewhere (on the heap) to store the current values of a, b, and c?
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.
Alexander Shishkin
2011-11-05 21:58:15 UTC
Permalink
Post by Michael Van Canneyt
Post by Bernd
Post by Marco van de Voort
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.
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.
How would you preserve the context without finding some place
somewhere (on the heap) to store the current values of a, b, and c?
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
end;
No difference with 'closure', except more readable.
Michael.
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
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).
Florian Klämpfl
2011-11-06 11:53:04 UTC
Permalink
Post by Alexander Shishkin
Post by Michael Van Canneyt
Post by Bernd
Post by Marco van de Voort
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.
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.
How would you preserve the context without finding some place
somewhere (on the heap) to store the current values of a, b, and c?
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
end;
No difference with 'closure', except more readable.
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).
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.
Alexander Shishkin
2011-11-06 13:00:34 UTC
Permalink
Post by Florian Klämpfl
Post by Alexander Shishkin
Post by Michael Van Canneyt
Post by Bernd
Post by Marco van de Voort
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.
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.
How would you preserve the context without finding some place
somewhere (on the heap) to store the current values of a, b, and c?
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
end;
No difference with 'closure', except more readable.
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).
Of course, but what Michael means is: closure support does not require
necessarily anonymous proceudures/functions/methods.
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
end;
We don't need lambda expressions after all to implement controll
statements like e.g. smalltalk.
_______________________________________________
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
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".
dmitry boyarintsev
2011-11-06 14:13:44 UTC
Permalink
Post by Alexander Shishkin
OK, 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.
Jonas Maebe
2011-11-06 14:21:01 UTC
Permalink
Post by dmitry boyarintsev
Hi-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.
Post by dmitry boyarintsev
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.
Post by dmitry boyarintsev
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
Alexander Shishkin
2011-11-06 15:17:35 UTC
Permalink
Post by dmitry boyarintsev
Post by Alexander Shishkin
OK, 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?
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.
Post by dmitry boyarintsev
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
Florian Klämpfl
2011-11-06 15:24:02 UTC
Permalink
Post by dmitry boyarintsev
Post by Alexander Shishkin
OK, 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?
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.
Jürgen Hestermann
2011-11-06 17:24:16 UTC
Permalink
Post by Florian Klämpfl
Post by 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.
Post by Florian Klämpfl
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.
Florian Klämpfl
2011-11-06 18:14:26 UTC
Permalink
Post by Jürgen Hestermann
Post by Florian Klämpfl
Post by 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?
Feel free to start a fork and we will see what will make it into trunk.
Post by Jürgen Hestermann
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.
Post by Jürgen Hestermann
Post by Florian Klämpfl
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?
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.
Jürgen Hestermann
2011-11-06 18:21:22 UTC
Permalink
Post by Florian Klämpfl
Post by Jürgen Hestermann
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?
Post by Florian Klämpfl
Post by Jürgen Hestermann
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?
Post by Florian Klämpfl
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.
Jonas Maebe
2011-11-06 18:41:18 UTC
Permalink
Post by Florian Klämpfl
Post by Jürgen Hestermann
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?
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
Jürgen Hestermann
2011-11-07 17:45:47 UTC
Permalink
Post by Jonas Maebe
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).
Jonas Maebe
2011-11-07 19:09:23 UTC
Permalink
Post by Jonas Maebe
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
Jürgen Hestermann
2011-11-08 06:20:07 UTC
Permalink
Post by Jonas Maebe
Post by Jürgen Hestermann
Post by Jonas Maebe
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.
Post by Jonas Maebe
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.
Post by Jonas Maebe
It's not that longtime developers won't listen to other opinions,
But that's what you do when using your standard argument.
Florian Klaempfl
2011-11-08 07:17:06 UTC
Permalink
Post by Jürgen Hestermann
Post by Jonas Maebe
Post by Jürgen Hestermann
Post by Jonas Maebe
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.
Post by Jonas Maebe
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?
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).
Florian Klämpfl
2011-11-06 18:58:53 UTC
Permalink
Post by Jürgen Hestermann
Post by Florian Klämpfl
Post by Jürgen Hestermann
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?
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.
Post by Jürgen Hestermann
Post by Florian Klämpfl
Post by Jürgen Hestermann
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?
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.
Post by Jürgen Hestermann
Post by Florian Klämpfl
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.
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.
Martin Schreiber
2011-11-07 07:10:30 UTC
Permalink
Post by Jürgen Hestermann
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.
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
Jonas Maebe
2011-11-07 09:55:41 UTC
Permalink
Post by Martin Schreiber
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.
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
Martin Schreiber
2011-11-07 10:28:43 UTC
Permalink
Post by Jonas Maebe
Post by Martin Schreiber
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.
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".
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
Jonas Maebe
2011-11-07 10:42:42 UTC
Permalink
Post by Martin Schreiber
Post by Jonas Maebe
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".
Is there a big demand? Examples?
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).
Post by Martin Schreiber
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.
Post by Martin Schreiber
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.
Post by Martin Schreiber
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
Luiz Americo Pereira Camara
2011-11-07 16:02:59 UTC
Permalink
Post by Martin Schreiber
Post by Jonas Maebe
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".
Is there a big demand? Examples?
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
Martin Schreiber
2011-11-07 16:38:53 UTC
Permalink
Post by Luiz Americo Pereira Camara
Post by Martin Schreiber
Is there a big demand? Examples?
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/
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
Bernd
2011-11-06 13:41:39 UTC
Permalink
Post by Michael Van Canneyt
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
end;
Why would this function have an argument list? How would the target
thread call it?
Bernd
2011-11-05 22:25:23 UTC
Permalink
Post by Michael Van Canneyt
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
end;
No difference with 'closure', except more readable.
Michael.
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.
Michael Van Canneyt
2011-11-06 00:30:15 UTC
Permalink
Post by Bernd
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.
Bernd
2011-11-06 11:41:58 UTC
Permalink
Post by 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
Bernd
2011-11-05 19:02:42 UTC
Permalink
Post by Marco van de Voort
targethread.queue(
  procedure(targetobject:ttargetobject;a:integer;b:someobject;c:string)
             begin
               targetobject.destinationprocedure(a,b,c);
             end;
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.
Marco van de Voort
2011-10-25 11:52:06 UTC
Permalink
Post by m***@wisa.be
Post by Marco van de Voort
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.
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.
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.
m***@wisa.be
2011-10-25 11:58:04 UTC
Permalink
Post by Marco van de Voort
Post by m***@wisa.be
Post by Marco van de Voort
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.
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.
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.
Lukasz Sokol
2011-10-26 08:44:00 UTC
Permalink
Post by Marco van de Voort
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.
[OT]
It's the Let's Screw FPC Guys Life [LSFGL] warrior call of the Borland/CodeGear/Embracadero
employees ;)

L.
Lukasz Sokol
2011-10-26 11:47:06 UTC
Permalink
Post by Marco van de Voort
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.
[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.
Marco van de Voort
2011-11-05 19:08:10 UTC
Permalink
Post by Bernd
Post by Marco van de Voort
targethread.queue(
? procedure(targetobject:ttargetobject;a:integer;b:someobject;c:string)
? ? ? ? ? ? ?begin
? ? ? ? ? ? ? ?targetobject.destinationprocedure(a,b,c);
? ? ? ? ? ? ?end;
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.
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.
Marco van de Voort
2011-11-07 18:41:35 UTC
Permalink
Post by Martin Schreiber
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.
Graeme Geldenhuys
2011-11-08 06:35:49 UTC
Permalink
Post by Marco van de Voort
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.
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.
--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
Florian Klaempfl
2011-11-08 07:23:04 UTC
Permalink
Post by Graeme Geldenhuys
Post by Marco van de Voort
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.
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.
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.
Graeme Geldenhuys
2011-11-08 08:01:03 UTC
Permalink
Post by Florian Klaempfl
Writing an (L)GPL'ed pascal (*) compiler being self hosting.
Tomas Hajny
2011-11-08 08:04:48 UTC
Permalink
Post by Florian Klaempfl
Writing an (L)GPL'ed pascal (*) compiler being self hosting.
Graeme Geldenhuys
2011-11-08 08:37:19 UTC
Permalink
Post by Martin Schreiber
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).
--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
Tomas Hajny
2011-11-08 09:59:56 UTC
Permalink
Post by Graeme Geldenhuys
Post by Martin Schreiber
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).
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
Florian Klaempfl
2011-11-08 10:43:42 UTC
Permalink
Post by Graeme Geldenhuys
Post by Martin Schreiber
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).
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?
Graeme Geldenhuys
2011-11-08 12:14:03 UTC
Permalink
Post by Florian Klaempfl
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.
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?
Post by Florian Klaempfl
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;
--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
Martin Schreiber
2011-11-08 08:23:15 UTC
Permalink
Post by Florian Klaempfl
Writing an (L)GPL'ed pascal (*) compiler being self hosting.
Marco van de Voort
2011-11-08 09:56:21 UTC
Permalink
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".
I fear the opposite: all Delphi "crap" will be implemented.
Don't worry, there is also room for FPC "crap" ("case string of" e.g.) :-)
Martin Schreiber
2011-11-08 10:48:26 UTC
Permalink
Post by Marco van de Voort
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".
I fear the opposite: all Delphi "crap" will be implemented.
Don't worry, there is also room for FPC "crap" ("case string of" e.g.) :-)
Which I like but not use because of Delphi 7 compatibility. :-)

Martin
Loading...