Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2013-03

Delphi anonymous methods

176 messages · 25 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

vrt277

Hi,

I want to implement support of Delphi anonymous methods for fpc. As I know I should create good proposal. Fortunately Delphi already made half of my work.
Proposal: all behaviour described in
http://docwiki.embarcadero.com/RADStudio/XE3/en/Anonymous_Methods_in_Delphi should be implemented.

Anonymous methods are like closures in other languages. Main features of anonymous methods and closures are
- access to local variables
- extend lifetime of used local variables.

Difference between anonymous methods in Delphi and closures in most other languages is that you can not create many instances of same anonymous methods during work of it's declaring function. I don't know how to say better, but example can help:

=begin example

type TProc = reference to Procedure;
var i: Integer;
     arr: array[1..5] of TProc;
begin
   for i := 1 to 5 do
     arr[i] :=
       procedure begin
       end;
   for i := 1 to 4 do
     Write(arr[i] = arr[i+1], ' ');
end.

=end example

Someone who thinks that first cycle creates different anonymous methods is wrong. All values in arr will be equal after cycle execution. Here more complicated example of same feature:
https://gist.github.com/vkevroletin/5069653

I investigated behaviour and implementation(slightly) of anonymous methods in Delphi. Results are in document below. It have little introduction which is not very useful for advanced developers but may be helpful in wiki to describe some aspects of compiler. Both links point to same document in different formats.
plain text:
https://raw.github.com/vkevroletin/Diploma/master/anonym_method_delphi.org pdf:
https://github.com/vkevroletin/Diploma/blob/master/anonym_method_delphi.pdf

Implementation of anonymous methods was started in the branch. Author didn't submit anything last year and forgot commit one added file. But changes from branch can be useful, AFAIU parsing of anonymous functions without capturing of local variables was implemented.

Does someone know is author available? Does he plan to continue work, or I can work on implementation without collaboration with him ? Or at least can he send missed file ?

It's hard to properly split this complex task into subtasks. I can propose 2 steps:
1. Parsing and generation of anonymous function. Capturing of variables is forbidden.
2. Capturing of variables is implemented.

A question for fpc team: do you agree that support of Delphi-compatible anonymous methods should be implemented?

Also there are open questions which require brainstorm:
1. Does Pascal needs other implementation of closures which is different from anonymous methods implementation?
2. Does Pascal needs short syntax for closures?
I if someone want to discuss these questions it will be better to create in separate threads.

Link to closures branch:
http://svn.freepascal.org/cgi-bin/viewvc.cgi/branches/blaise/closures/

Vasiliy K.

Reply by email

Sven Barth
to vrt277
vrt277 wrote 9 lines
Implementation of anonymous methods was started in the branch. Author didn't submit anything last year and forgot commit one added file. But changes from branch can be useful, AFAIU parsing of anonymous functions without capturing of local variables was implemented. Does someone know is author available? Does he plan to continue work, or I can work on implementation without collaboration with him ? Or at least can he send missed file ?

I have already written the author some time ago. He has said that he plans to at least commit the missing files. If you would continue his work (in a new branch please with a complete copy of trunk...) then he might be relieved as well.

Show quoted text 8 lines
It's hard to properly split this complex task into subtasks. I can propose 2 steps: 1. Parsing and generation of anonymous function. Capturing of variables is forbidden. 2. Capturing of variables is implemented. A question for fpc team: do you agree that support of Delphi-compatible anonymous methods should be implemented?

At least I do, yes.

Also there are open questions which require brainstorm: 1. Does Pascal needs other implementation of closures which is different from anonymous methods implementation?

I would say no. After all the method implementation itself stays the same, but the captured variables should be different. Or what does this print:

=== example begin ===

var
   arr: array[0..5] of reference to procedure;
   i: LongInt;
begin
   for i := Low(arr) to High(arr) do
     arr[i] := procedure
            begin
              Writeln(i);
            end;
   Writeln('Output: '); // just to ensure that the optimizer doesn't
combine the two loops
   for i := Low(arr) to High(arr) do
     arr[i]();
end;

=== example end ===

2. Does Pascal needs short syntax for closures?

I would say yes, but this can be done in a seperate step

I if someone want to discuss these questions it will be better to create in separate threads.

Two personal things I'd like to note as I have already planned to continue working on anonymous functions myself:
- add support to pass nested functions to "reference to" procvars; this will allow users who don't want to use the anonymous syntax to use the "closure" feature as well; please note that this must be done in a way that passing nested functions to "is nested" procvars is not broken
- (in context with the above point) couple the support for the anonymous functions to a new modeswitch (enabled by default in mode delphi), but allow "reference to" procvars in non-Delphi modes (this way you'd only be able to use nested functions, but later on the shorter syntax should be used there as well)

Regards,
Sven

Reply by email

ListMember
to Sven Barth
Sven Barth wrote 5 lines
- (in context with the above point) couple the support for the anonymous functions to a new modeswitch (enabled by default in mode delphi), but allow "reference to" procvars in non-Delphi modes (this way you'd only be able to use nested functions, but later on the shorter syntax should be used there as well)

This paragraph went way over my head.

But, it sort of reminded me to ask about something else:

Are anonymous methods (going to be) compatible with event methods?

i.e. are they 'procedure of object' (or 'function of object') kind of constructs.

The reason I am asking this is: There have been times when I could kill to be able to assign (temporarily) a local procedure/function an object's event (say, OnClick) so that I could capture the event's outcome right in there wthin the body of the active routine.

Would this be possible?

Reply by email

Sven Barth
to ListMember
ListMember wrote 22 lines
On 2013-03-02 21:55, Sven Barth wrote: > - (in context with the above point) couple the support for the > anonymous functions to a new modeswitch (enabled by default in mode > delphi), but allow "reference to" procvars in non-Delphi modes (this > way you'd only be able to use nested functions, but later on the > shorter syntax should be used there as well) This paragraph went way over my head. But, it sort of reminded me to ask about something else: Are anonymous methods (going to be) compatible with event methods? i.e. are they 'procedure of object' (or 'function of object') kind of constructs. The reason I am asking this is: There have been times when I could kill to be able to assign (temporarily) a local procedure/function an object's event (say, OnClick) so that I could capture the event's outcome right in there wthin the body of the active routine. Would this be possible?

In theory one could extend the "reference to" procvars to handle normal methods as well. But then the event handler would need to be defined as a "reference to" procvar as well instead of an "of object" one. An "of object" procvar on the other hand is too fixed. Only the new procvar type introduced together with anonymous functions would be flexible enough so that it could be used as a replacement for all other procvars (if implemented correctly in the compiler).

Regards,
Sven

Reply by email

Sven Barth
to Sven Barth: I have already written the author some time ago. He has said that he plans to at least…
Sven Barth wrote 7 lines
> Also there are open questions which require brainstorm: > 1. Does Pascal needs other implementation of closures which is different > from anonymous methods implementation? I would say no. After all the method implementation itself stays the same, but the captured variables should be different. Or what does this print:

I've now read through your PDF and somehow I'd like to have a better implementation in FPC. Let's consider the following code (Note: I've never used anonymous methods yet, so this is what I naively would expect):

=== code begin ===

var
   i: LongInt;
   SomeProc1, SomeProc2: reference to procedure;
begin
   i := 42;
   SomeProc1 := procedure
                begin
                  Writeln('Proc1: ' + i);
                end;
   i := 21;
   SomeProc2 := procedure
                begin
                  Writeln('Proc2: ' + i);
                end;
   SomeProc1;
   SomeProc2;
end;

=== code end ===

The output I'd expect here is the following:

=== output begin ===

42
21

=== output end ===

But if I've understood you correctly I'll get the following instead:

=== output begin ===

21
21

=== output end ===

I don't like this -.-

You also wrote that local variables seem to be located on the FrameObject. So how is it with multi threading? E.g.

=== example begin ===

for i := 0 to 5 do
   TThread.CreateAnonymousThread(
     procedure
     var
       x: LongInt;
     begin
       x := Random;
       Writeln('Before ', TThread.CurrentThread.ThreadID, ': ', x);
       Sleep(x);
       Writeln('After ', TThread.CurrentThread.ThreadID, ': ', x);
     end).Start;

=== example end ===

If the "x" is really located in the FrameObject and that object exists only once then it is rather likely that the output of 'Before 123: ' is different from the output of 'After 123: ', right? Again I think this is a bad thing...

So in my opinion an implementation with a stricter division between the single instances of an anonymous function would be the better choice. Also local variables should reside on the stack of the anonymous function... as we generate the code of nested procedures/functions only after the complete outer function was parsed (and AFAIK also had its code generated) we should be able to "easily" add the generation of anonymous function bodies as well. So we should have multiple smaller objects storage objects that only contain those variables of the outer function and those nested functions that are really used instead of one big FrameObject. It might be quite a bit harder to implement in a correct and good (and maybe also performant) way, but we would - at least in my opinion - gain a more logical and straight implementation of closures.

Regards,
Sven

Reply by email

Vasiliy Kevroletin
to Sven Barth
Show quoted text 11 lines
=== output end === But if I've understood you correctly I'll get the following instead: === output begin === 21 21 === output end ===

Right
You want to capture variable by value. For example lambdas in c++ have special syntax to choose how to capture. By reference or by value. Capturing by value is useful to make parametrized anonymous functions. Capturing by reference is useful to change local variables. In other c-like languages if you have capturing by reference you can simply simulate capturing by value. You can wrap anonymous function into a block and declare local variable in this block.

Example:
=== begin perl ===

for my $i (0 .. 9)
{

     my $copy = $i;
     $f[$i] = sub {
         printf($copy);
     };

}

$f[0]->(); #0
$f[9]->(); #9

=== end perl ===

Javascript is more like Delphi. Scope of variable in javascript restricted by entire declaring function not by declaring block. So you should do something like this:

=== begin javascript ===

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0]();
f[9]();

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0](); // 0
f[9](); // 9

=== end javascript ===

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0]();
f[9]();
You also wrote that local variables seem to be located on the FrameObject. So how is it with multi threading? E.g.

I missed test with multithreading and made wrong assumption.

Sven's test:
=== test begin ===

   for i := 0 to 1 do
     TThread.CreateAnonymousThread(
       procedure
       var
         x: LongInt;
       begin
         Writeln('Address ', TThread.CurrentThread.ThreadID, ': 0x',
IntToHex(Integer(@x), 8));
         x := Round(Random*100);
         Writeln('Before ', TThread.CurrentThread.ThreadID, ': ', x);
         Sleep(5000);
         Writeln('After ', TThread.CurrentThread.ThreadID, ': ', x);
       end).Start;

=== test end ===

=== output begin ===

Address 2028: 0x00F3FF68
Before 2028: 0
Address 2176: 0x0103FF68
Before 2176: 3
After 2028: 0
After 2176: 3

=== output end ====

There are different local variables in different threads. But in one thread local variables are same.

=== test begin ===

   for i := 0 to 1 do
     f[i] :=  procedure
              var x: Integer;
              begin
                Writeln('Address ', TThread.CurrentThread.ThreadID, ': 0x',
                        IntToHex(Integer(@x), 8));
              end;
   Writeln(' ');
   for i := 0 to 1 do
     f[i]();

=== test end ===

=== output begin ===

Address 3364: 0x0012FF98
Address 3364: 0x0012FF98

=== output end ===

Do you have any ideas how and why such behaviour implemented ?

Vasiliy K.

Reply by email

vrt277
to Sven Barth: I've now read through your PDF and somehow I'd like to have a better implementation in…
Show quoted text 11 lines
=== output end === But if I've understood you correctly I'll get the following instead: === output begin === 21 21 === output end ===

Right
You want to capture variable by value. For example lambdas in c++ have special syntax to choose how to capture. By reference or by value. Capturing by value is useful to make parametrized anonymous functions. Capturing by reference is useful to change local variables. In other c-like languages if you have capturing by reference you can simply simulate capturing by value. You can wrap anonymous function into a block and declare local variable in this block.

Example:
=== begin perl ===

for my $i (0 .. 9)
{

     my $copy = $i;
     $f[$i] = sub {
         printf($copy);
     };

}

$f[0]->(); #0
$f[9]->(); #9

=== end perl ===

Javascript is more like Delphi. Scope of variable in javascript restricted by entire declaring function not by declaring block. So you should do something like this:

=== begin javascript ===

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0]();
f[9]();

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0](); // 0
f[9](); // 9

=== end javascript ===

for (i = 0; i < 10; ++i)
{
(function () {

         var copy = i;
         f[i] = function () {
             alert(copy);
         }
     })()

}

f[0]();
f[9]();
You also wrote that local variables seem to be located on the

FrameObject. So how is it with multi threading? E.g. I missed test with multithreading and made wrong assumption.

Sven's test:
=== test begin ===

   for i := 0 to 1 do
     TThread.CreateAnonymousThread(
       procedure
       var
         x: LongInt;
       begin
         Writeln('Address ', TThread.CurrentThread.ThreadID, ': 0x',
IntToHex(Integer(@x), 8));
         x := Round(Random*100);
         Writeln('Before ', TThread.CurrentThread.ThreadID, ': ', x);
         Sleep(5000);
         Writeln('After ', TThread.CurrentThread.ThreadID, ': ', x);
       end).Start;

=== test end ===

=== output begin ===

Address 2028: 0x00F3FF68
Before 2028: 0
Address 2176: 0x0103FF68
Before 2176: 3
After 2028: 0
After 2176: 3

=== output end ====

There are different local variables in different threads. But in one thread local variables are same.

=== test begin ===

   for i := 0 to 1 do
     f[i] :=  procedure
              var x: Integer;
              begin
                Writeln('Address ', TThread.CurrentThread.ThreadID, ': 0x',
                        IntToHex(Integer(@x), 8));
              end;
   Writeln(' ');
   for i := 0 to 1 do
     f[i]();

=== test end ===

=== output begin ===

Address 3364: 0x0012FF98
Address 3364: 0x0012FF98

=== output end ===

Do you have any ideas how and why such behaviour implemented ?

Vasiliy K.

Reply by email

Vasiliy Kevroletin
to Vasiliy Kevroletin: Right You want to capture variable by value. For example lambdas in c++ have special…
Do you have any ideas how and why such behaviour implemented ?

Now I can answer my question myself. *Local variables of anonymous method are located on stack*.

This assumption is based on 2 points:

1.

assignment to local variable of anonymous function

x := 10;

will become this

mov [ebp - $04], $a

=== full example ===

begin
   Call( procedure
         var x: Integer;
         begin
           x := 10;          { mov [ebp - $04], $a }
           Writeln(x);
         end );
end.

===

2. example

https://gist.github.com/vkevroletin/5069653
output for example is in first comment after code.

Vasiliy

P.S.

In last email I pasted one javascript example 3 times accidentally. I was writing from before because emails from my main mailbox wasn't delivered to mail list.

Reply by email

Boian Mitov
to Vasiliy Kevroletin

Hi Vasiliy,

Just some additional info in case you are not aware. Delphi implements the anonymous methods as interfaces, and that is how it keeps them alive.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 9 lines
-----Original Message----- From: Vasiliy Kevroletin Sent: Saturday, March 02, 2013 9:08 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods Now I can answer my question myself. *Local variables of anonymous method are located on stack*.

Reply by email

Vasiliy Kevroletin
to Sven Barth: I've now read through your PDF and somehow I'd like to have a better implementation in…
If the "x" is really located in the FrameObject and that object exists only once then it is rather likely that the output of 'Before 123: ' is different from the output of 'After 123: ', right? Again I think this is a bad thing...

I was wrong. Local variables of anonymous function located where they should be: on stack.

So in my opinion an implementation with a stricter division between the single instances of an anonymous function would be the better choice

Am I understand correctly that loop

for i := 1 to 5 do
   procArr[i] := procedure begin
                          DoSmth();
                        end;

should create 5 separate instances?
It is as I thought about closures before. But this is useless without capturing of variables by value. During creation of anonymous method you *can not bind any values* to it. Anonymous method have only references to captured variables. Pascal don't allows to create static variables inside function like in c-like languages. So you also not able to create unique static variable which available only to one instance of same anonymous method. Even if implementation will create many separate objects for one anonymous function then all instances will be equivalent. Because all instances will refer to same data.

Capturing variables by value will allow simple creation of parametrised closures. Now you also can do parametrised anonymous method but you should wrap generation of such method into other anonymous function. For example like this:

=== example

for i := 1 to 5 do
   procArr[i] := Call(
     function: TProc
     var stored: Integer;
     begin
       stored := i;
       Result := procedure
                 begin
                   Writeln(stored);
                 end;
     end );

===

This can be simplified by support of capturing by value (please don't make many attention to syntax, it's not main part of my proposal).

=== example

for i := 1 to 5 do
   procArr[i] := procedure
                        capture i: byValue;
                        begin
                          Writeln(i);
                       end;
     end );

===

What do you think about extension which will allow to specify how to capture. Either by value or by reference?

Vasiliy K.

Reply by email

Sven Barth
to Vasiliy Kevroletin
Vasiliy Kevroletin wrote 6 lines
> If the "x" is really located in the FrameObject and that object exists > only once then it is rather likely that the output of 'Before 123: ' > is different from the output of 'After 123: ', right? Again I think > this is a bad thing... I was wrong. Local variables of anonymous function located where they should be: on stack.

That's a relieve :)

Show quoted text 10 lines
> So in my opinion an implementation with a stricter division between > the single instances of an anonymous function would be the better choice Am I understand correctly that loop for i := 1 to 5 do procArr[i] := procedure begin DoSmth(); end; should create 5 separate instances?

Not the code should be seperate, but where the captured data is located. In Delphi there will only be one FrameObject shared by all anonymous functions, but in my opinion it would be better if we have each a "Storage Object" for each "instance" of an anonymous function. So in the above example there would indeed be 5 such instance (but the code would only exist once).

Show quoted text 9 lines
It is as I thought about closures before. But this is useless without capturing of variables by value. During creation of anonymous method you *can not bind any values* to it. Anonymous method have only references to captured variables. Pascal don't allows to create static variables inside function like in c-like languages. So you also not able to create unique static variable which available only to one instance of same anonymous method. Even if implementation will create many separate objects for one anonymous function then all instances will be equivalent. Because all instances will refer to same data.

Little side note: You can create static variables in Pascal, it's just not as you'd expect them ;)

=== example begin ===

procedure Test;
const
   FooBar: Integer = 42;
begin
   Writeln(FooBar);
{$push}
{$J+}
   FooBar := 21;
{$pop}
end;
Test; // 42
Test; // 21

=== example end ===

This works since at least Turbo Pascal times (and the $J enables writeable typed constants) and was used as the "poor man's visibility handling"

But I don't understand what you continue to write: if we create a static variable it would be shared by all instances and not be specific to each instance.
Also in my proposal the instances would not be equivalent. Delphi seems to create these anonymous functions

=== code begin ===

procedure Something;
var
   x, y: Integer;
   proc: reference to procedure;
   func: reference to function(aX: Integer): Integer;
begin
   x := 42;
   y := 21;
   proc := procedure
           begin
             Writeln(x);
           end;
   func := function(aX: Integer): Integer
           begin
             Result := aX * y;
           end;
end;

=== code end ===

this way (note: not necessarily compileable code):

=== code begin ===

procedure Something;
   type
     FrameObjectClass = class(TInterfacedObject)
       x, y: Integer;
       procedure CallProc1;
       function CallFunc1(aX: Integer): Integer;
     end;
     procedure FrameObjectClass.CallProc1;
     begin
       Writeln(x);
     end;
     function FrameObjectClass.CallFunc1(aX: Integer): Integer;
     begin
       Result := aX * y;
     end;
   var
     FrameObject: FrameObjectClass;
     proc: reference to procedure;
     func: reference to function(aX: Integer): Integer;
begin
   FrameObject := FrameObjectClass.Create;
   FrameObject.x := 42;
   FrameObject.y := 21;
   proc := @FrameObject.CallProc1;
   func := @FrameObject.CallFunc1;
end;

=== code end ===

Now I would like to see it done like this:

=== code begin ===

procedure Something;
type
   StorageProc1 = class(TInterfacedObject)
     x: Integer;
     procedure Invoke;
   end;
   StorageFunc1 = class(TInterfacedObject)
     y: Integer;
     function Invoke(aX: Integer): Integer;
   end;
var
   x, y: Integer;
   tmp: TInterfacedObject;
   proc: reference to procedure;
   func: reference to function(aX: Integer): Integer;
begin
   x := 42;
   y := 21;
   tmp := StorageProc1.Create;
   tmp.x := x;
   proc := @tmp.Invoke;
   tmp := STorageProc1.Create;
   tmp.y := y;
   func := @tmp.Invoke;
end;

=== code end ===

Note: I'm aware that one shouldn't use interfaces this way; this is only an example that should illustrate my point.

So for each assignment to a "reference to" procvar a new such Storage Object will be created and so a "arr[1] = arr[2]" would be false in case of the loop.

Show quoted text 38 lines
Capturing variables by value will allow simple creation of parametrised closures. Now you also can do parametrised anonymous method but you should wrap generation of such method into other anonymous function. For example like this: === example for i := 1 to 5 do procArr[i] := Call( function: TProc var stored: Integer; begin stored := i; Result := procedure begin Writeln(stored); end; end ); === This can be simplified by support of capturing by value (please don't make many attention to syntax, it's not main part of my proposal). === example for i := 1 to 5 do procArr[i] := procedure capture i: byValue; begin Writeln(i); end; end ); === What do you think about extension which will allow to specify how to capture. Either by value or by reference?

Maybe specifying how a variable should be captured would be a solution that can satisfy both worlds...

Regards,
Sven

Reply by email

Vasiliy Kevroletin
to Sven Barth
Sven Barth wrote 10 lines
On 03.03.2013 06:08, Vasiliy Kevroletin wrote: > >> Do you have any ideas how and why such behaviour implemented ? >> > Now I can answer my question myself. *Local variables of anonymous > method are located on stack*. I would have wondered about the state of mind of the Embarcadero developers if it would have been different :P

Yes, now I don't sure how I did such assumption. May be I was under expression of fact that SizeOf(TProc) = 4 (on 32-bit machine).

Reply by email

Vasiliy Kevroletin
to Sven Barth: That's a relieve :) Not the code should be seperate, but where the captured data is…
Maybe specifying how a variable should be captured would be a solution that can satisfy both worlds...

Good.

This will also help to split implementation.
1. Implement Sven's proposal. Anonymous functions which can capture local variables only by value.
2. Create Delphi-compatible capturing by reference.
3. Discuss and implement short lambdas syntax.

Vasiliy K.

Reply by email

Sven Barth
to Vasiliy Kevroletin
Vasiliy Kevroletin wrote 11 lines
> Maybe specifying how a variable should be captured would be a solution > that can satisfy both worlds... Good. This will also help to split implementation. 1. Implement Sven's proposal. Anonymous functions which can capture local variables only by value. 2. Create Delphi-compatible capturing by reference. 3. Discuss and implement short lambdas syntax.

Yes, this can be seen as a plan. We also need to think about a approbiate syntax for 1 before this step can be done. And I'd also like to know what other core devs think about this. I myself would support this though.

And I'll also ask Blaise whether he can commit the missing code so that you could in principal use his work as a base.

Regards,
Sven

Reply by email

Alexander Klenin
to Sven Barth
Sven Barth wrote 10 lines
> This will also help to split implementation. > 1. Implement Sven's proposal. Anonymous functions which can capture > local variables only by value. > 2. Create Delphi-compatible capturing by reference. > 3. Discuss and implement short lambdas syntax. Yes, this can be seen as a plan. We also need to think about a approbiate syntax for 1 before this step can be done. And I'd also like to know what other core devs think about this. I myself would support this though.

I agree with the plan. But I am not sure about the order -- perhaps implement Delphi-compatible variant first, since it have to be done anyway, and there is already a spec for it.

Alexander S. Klenin

Reply by email

Paul Ishenin
to Alexander Klenin

03.03.13, 22:09, Alexander Klenin пишет:

I agree with the plan. But I am not sure about the order -- perhaps implement Delphi-compatible variant first, since it have to be done anyway, and there is already a spec for it.

I also vote for Delphi-compatible feature the first, then implement extensions.

Best regards,
Paul Ishenin

Reply by email

Sven Barth
to Alexander Klenin: I agree with the plan. But I am not sure about the order -- perhaps implement…
Alexander Klenin wrote 16 lines
On Sun, Mar 3, 2013 at 11:21 PM, Sven Barth wrote: >> This will also help to split implementation. >> 1. Implement Sven's proposal. Anonymous functions which can capture >> local variables only by value. >> 2. Create Delphi-compatible capturing by reference. >> 3. Discuss and implement short lambdas syntax. > > > Yes, this can be seen as a plan. We also need to think about a approbiate > syntax for 1 before this step can be done. And I'd also like to know what > other core devs think about this. I myself would support this though. I agree with the plan. But I am not sure about the order -- perhaps implement Delphi-compatible variant first, since it have to be done anyway, and there is already a spec for it.

Implementing the Delphi compatible behavior first might prohibit the alternative behavior. So first an analysis step should be added to evaluate how the two ways can be implemented without prohibiting one of the two ways.

Regards,
Sven

Reply by email

Graeme Geldenhuys
to vrt277: I want to implement support of Delphi anonymous methods for fpc. As I know I should…
vrt277 wrote
I want to implement support of Delphi anonymous methods for fpc.

Just curious... why must such a feature be allowed in Object Pascal? Referring to the recent "butchering of the Object Pascal language" thread we had recently in fpc-pascal.

It was clearly stated in the past that FPC will not support the C/C++ language feature of declaration a variable in-line inside code blocks, but only in var sections.

Example of not allowed code:

  for i: integer = 0 to 10 do
  begin
  end;

or

  var
    s: string;
  begin
    s := 'string'
    ...
    i: integer := 0;     // I must be declared in var section instead
    Inc(i, 5);
    ...
  end;
From what I can see, anonymous methods are just like the above code...

allowing a declaration of a procedure/method in-line inside a code block where in shouldn't belong. It is very, very un-Pascal like. The end result is unreadable code, probably hard to debug etc.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Marcos Douglas
to Graeme Geldenhuys
Graeme Geldenhuys wrote 36 lines
On 2013-03-02 19:03, vrt277 wrote: > > I want to implement support of Delphi anonymous methods for fpc. Just curious... why must such a feature be allowed in Object Pascal? Referring to the recent "butchering of the Object Pascal language" thread we had recently in fpc-pascal. It was clearly stated in the past that FPC will not support the C/C++ language feature of declaration a variable in-line inside code blocks, but only in var sections. Example of not allowed code: for i: integer = 0 to 10 do begin end; or var s: string; begin s := 'string' ... i: integer := 0; // I must be declared in var section instead Inc(i, 5); ... end; >From what I can see, anonymous methods are just like the above code... allowing a declaration of a procedure/method in-line inside a code block where in shouldn't belong. It is very, very un-Pascal like. The end result is unreadable code, probably hard to debug etc.

+1

Marcos Douglas

Reply by email

Boian Mitov
to Graeme Geldenhuys: Just curious... why must such a feature be allowed in Object Pascal? Referring to the…

Strongly disagree.
Anonymous methods are a critical feature of any mother language, and allow vast improvements of the code and the readability. I recently started rewriting our libraries with anonymous methods and that alone allowed for cutting over 20000 lines of code, while adding vast number of new features. Any language that does not support anonymous methods is just a joke IMHO.

If you have never developed with them, (as was I), you never know what you have been missing. They are actually more important than having object oriented support IMHO.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

From what I can see, anonymous methods are just like the above code...

allowing a declaration of a procedure/method in-line inside a code block where in shouldn't belong. It is very, very un-Pascal like. The end result is unreadable code, probably hard to debug etc.

Reply by email

Martin
to Boian Mitov
Boian Mitov wrote 8 lines
Strongly disagree. Anonymous methods are a critical feature of any mother language, and allow vast improvements of the code and the readability. I recently started rewriting our libraries with anonymous methods and that alone allowed for cutting over 20000 lines of code, while adding vast number of new features. Any language that does not support anonymous methods is just a joke IMHO.

Really, just by dropping the names? Or did you mean, you did all that by using closures?

> From what I can see, anonymous methods are just like the above code... allowing a declaration of a procedure/method in-line inside a code block where in shouldn't belong. It is very, very un-Pascal like. The end result is unreadable code, probably hard to debug etc.

Closures, do not need to be written/declared in the middle of other code (in-line)

Reply by email

Boian Mitov
to Martin

Yes, really!
Then again this is over 4 mln mines of code after all. :-D Thank you for letting me know what closure is :-D . Can you imagine, me being component vendor for over 16 years and not knowing what closure is :-D.
Anonymous methods lead to a different way of thinking altogether and allow you to do things that you can't even imagine with closures ;-) . And they make the code infinitely easier to read, especially if like me this is a huge codebase ;-) . After all we sell well over 400 components not to mention some of our other Delphi based products ;-) . Sure, if you have small code you can do just fine with closures, as I have for many years, then again I did just fine without having classes, and objects in the old days, and also did fine in the older days in Assembler :-D .
So according to this logic, we really should be doing everything in machine code (as I actually did briefly 24 years ago :-D ), who needs new features such as those whatmacallit... ohhh yeahh... "compilers" :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 12 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 7:38 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 01:47, Boian Mitov wrote: Really, just by dropping the names? Or did you mean, you did all that by using closures? Closures, do not need to be written/declared in the middle of other code (in-line)

Reply by email

Boian Mitov
to Martin: Really, just by dropping the names? Or did you mean, you did all that by using closures?…

Actually the biggest benefit was that it now allows me to design parallel execution code of complexity I was not able to design otherwise. I am just starting to scratch the surface. Hell... I have not even started really using the anonymous methods yet :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 9 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 7:38 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 01:47, Boian Mitov wrote: Really, just by dropping the names? Or did you mean, you did all that by using closures?

Reply by email

Alexander Klenin
to Graeme Geldenhuys: Just curious... why must such a feature be allowed in Object Pascal? Referring to the…
Graeme Geldenhuys wrote
>From what I can see, anonymous methods are just like the above code... allowing a declaration of a procedure/method in-line inside a code block where in shouldn't belong. It is very, very un-Pascal like.

Because computer science is advancing, and there is a limit after which programming language can not ignore those advancements and stay relevant. Imagine Pascal without records, or enumerated types, or properties, or built-in strings.
These are all "revolutionary" features that were introduced to the language at various stages of its development -- some at the inception, some later. Now, that does not mean that a particular Delphi implementation of some features is optimal, and we do discuss options in this thread.

Alexander S. Klenin

Reply by email

Boian Mitov
to Alexander Klenin

100% agree "revolutionary" is a very good word to describe it indeed! :-) . I remember people asking in the old days, why we need objects. Those ware old school Pascal people claiming that they can do just fine with records, and who needs classes :-D . They ware so un Pascal ! :-D . I am not kidding, I really new such people personally :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 9 lines
-----Original Message----- From: Alexander Klenin Sent: Sunday, March 03, 2013 7:59 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods These are all "revolutionary" features that were introduced to the language at various stages of its development -- some at the inception, some later.

Reply by email

Martin
to Boian Mitov: Yes, really! Then again this is over 4 mln mines of code after all. :-D Thank you for…
Boian Mitov wrote 5 lines
Yes, really! Then again this is over 4 mln mines of code after all. :-D Thank you for letting me know what closure is :-D . Can you imagine, me being component vendor for over 16 years and not knowing what closure is :-D.

Did I? Wow, I didn't know I did. Didn't mean to neither. I was just checking, if you accidentally used the wrong word. (Happens to everyone, even the very best / so no judgement implied)

Show quoted text 13 lines
Anonymous methods lead to a different way of thinking altogether and allow you to do things that you can't even imagine with closures ;-) . And they make the code infinitely easier to read, especially if like me this is a huge codebase ;-) . After all we sell well over 400 components not to mention some of our other Delphi based products ;-) . Sure, if you have small code you can do just fine with closures, as I have for many years, then again I did just fine without having classes, and objects in the old days, and also did fine in the older days in Assembler :-D . So according to this logic, we really should be doing everything in machine code (as I actually did briefly 24 years ago :-D ), who needs new features such as those whatmacallit... ohhh yeahh... "compilers" :-D .

Well I give you the benefit of the doubt, and believe you. But that does not help me, because I still do not know which case you are talking about.... So for my benefit, please enlighten me with an example.

From your above statement, I take, that you already used closures, and that the big improvements really happened of a result of anonymous methods. Just to be save, let me state the obvious: We are talking of dropping the function name; and introducing the ability, to declare the function anywhere within the code (probably the latter being the important). That are the 2 only things, that anonymous methods do offer? (OR am I missing anything?)

If so then I do not see how they save 20000 lines?
- The name is part of the declaration line, SO it should not affect the line count at all). Unless you always write the name on a separate line (which I would consider a very special case)
- the place of declaration also does not change the line count.

Show quoted text 11 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 7:38 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 01:47, Boian Mitov wrote: Really, just by dropping the names? Or did you mean, you did all that by using closures? Closures, do not need to be written/declared in the middle of other code (in-line)

Reply by email

Boian Mitov
to Martin

Here is example:

Parallel execution with selection of executor:

for i := 0 to AMaxScaleIndex - 1 do
  begin
  APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() );
  AExecutionTask.Add( AExecutor.Execute(
      procedure()
      begin
        ProcessOne( levelScale[ i ], img, hitThreshold, winStride, padding,
APerIterationLocations[ i ] );
      end
    ));
  end;

In this case, not only you save declaration, you save the need to write a whole new class just for the task.
This code reduced well over 30 lines of code alone. I have a lot of other examples as well ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 10 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 8:42 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 03:49, Boian Mitov wrote: Well I give you the benefit of the doubt, and believe you. But that does not help me, because I still do not know which case you are talking about.... So for my benefit, please enlighten me with an example.

Reply by email

Boian Mitov
to Boian Mitov

One thing for sure, I probably will very much never need to declare TThread inherited classes. I can use a single anonymous method for that, thanks to the ability of the anonymous method to capture local and member variables. This is something not doable with closure as it has fixed number of parameters ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 22 lines
-----Original Message----- From: Boian Mitov Sent: Sunday, March 03, 2013 8:54 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods Here is example: Parallel execution with selection of executor: for i := 0 to AMaxScaleIndex - 1 do begin APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); AExecutionTask.Add( AExecutor.Execute( procedure() begin ProcessOne( levelScale[ i ], img, hitThreshold, winStride, padding, APerIterationLocations[ i ] ); end )); end;

Reply by email

Boian Mitov
to Martin: Did I? Wow, I didn't know I did. Didn't mean to neither. I was just checking, if you…

Here is another even simpler example:

AItem := GComponentEditorList.Find(
                function( AItem : IComponentEditorItem ) : Boolean
                begin
                  Result := ( AComponent is
AItem.GetInstance().ComponentClass );
                end
             );

In this case you will either need additional member class variable (It will increase the memory usage), or you will need to declare a whole class just to achieve what I do with one line of code :-) . Sweet! :-)

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 59 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 8:42 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 03:49, Boian Mitov wrote: > Yes, really! > Then again this is over 4 mln mines of code after all. :-D > Thank you for letting me know what closure is :-D . Can you imagine, me > being component vendor for over 16 years and not knowing what closure is > :-D. Did I? Wow, I didn't know I did. Didn't mean to neither. I was just checking, if you accidentally used the wrong word. (Happens to everyone, even the very best / so no judgement implied) > Anonymous methods lead to a different way of thinking altogether and allow > you to do things that you can't even imagine with closures ;-) . > And they make the code infinitely easier to read, especially if like me > this is a huge codebase ;-) . After all we sell well over 400 components > not to mention some of our other Delphi based products ;-) . > Sure, if you have small code you can do just fine with closures, as I have > for many years, then again I did just fine without having classes, and > objects in the old days, and also did fine in the older days in Assembler > :-D . > So according to this logic, we really should be doing everything in > machine code (as I actually did briefly 24 years ago :-D ), who needs new > features such as those whatmacallit... ohhh yeahh... "compilers" :-D . Well I give you the benefit of the doubt, and believe you. But that does not help me, because I still do not know which case you are talking about.... So for my benefit, please enlighten me with an example. >From your above statement, I take, that you already used closures, and that the big improvements really happened of a result of anonymous methods. Just to be save, let me state the obvious: We are talking of dropping the function name; and introducing the ability, to declare the function anywhere within the code (probably the latter being the important). That are the 2 only things, that anonymous methods do offer? (OR am I missing anything?) If so then I do not see how they save 20000 lines? - The name is part of the declaration line, SO it should not affect the line count at all). Unless you always write the name on a separate line (which I would consider a very special case) - the place of declaration also does not change the line count. > -----Original Message----- From: Martin > Sent: Sunday, March 03, 2013 7:38 PM > To: FPC developers' list > Subject: Re: [fpc-devel] Delphi anonymous methods > > On 04/03/2013 01:47, Boian Mitov wrote: > Really, just by dropping the names? Or did you mean, you did all that by > using closures? > > Closures, do not need to be written/declared in the middle of other code > (in-line)

Reply by email

Boian Mitov
to Martin: Did I? Wow, I didn't know I did. Didn't mean to neither. I was just checking, if you…

Or even more drastic example like this one:

AAttributes := TRTRtti.GetType(
Component.ClassType() ).GetCustomAttributes(
TVLCommonFilterHostedPreviewAttribute, True );
for AAttribute in AAttributes do
  if( AAttribute is TLPComponentEditorAttribute ) then
    begin
    AAttrItem := GComponentEditorAttributeList.Find(
                      function( AItem : IComponentEditorAttributeItem ) :
Boolean
                      var
                        AAttributes     : IRTAttributes;
                        AAttributeClass : TCustomAttributeClass;
                      begin
                        AAttributeClass :=
AItem.GetInstance().AttributeClass;
                        AAttributes := TRTRtti.GetType(
Component.ClassType() ).GetCustomAttributes( TLPSuppressAttribute, True );
                        if( AAttributes.Find(
                                function ( ASupressAttribute :
TCustomAttribute ) : Boolean
                                begin
                                  Result := ( AAttributeClass =
TLPSuppressAttribute( ASupressAttribute ).Attribute );
                                end
                              )  NIL ) then
                          Exit( False );
                        Result := ( AAttribute is AAttributeClass );
                      end
                   );
    Exit( AAttrItem.GetInstance().ComponentEditor.Create( Component,
Designer ));
    end;

Try to write this without anonymous methods ;-) :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 59 lines
-----Original Message----- From: Martin Sent: Sunday, March 03, 2013 8:42 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 03:49, Boian Mitov wrote: > Yes, really! > Then again this is over 4 mln mines of code after all. :-D > Thank you for letting me know what closure is :-D . Can you imagine, me > being component vendor for over 16 years and not knowing what closure is > :-D. Did I? Wow, I didn't know I did. Didn't mean to neither. I was just checking, if you accidentally used the wrong word. (Happens to everyone, even the very best / so no judgement implied) > Anonymous methods lead to a different way of thinking altogether and allow > you to do things that you can't even imagine with closures ;-) . > And they make the code infinitely easier to read, especially if like me > this is a huge codebase ;-) . After all we sell well over 400 components > not to mention some of our other Delphi based products ;-) . > Sure, if you have small code you can do just fine with closures, as I have > for many years, then again I did just fine without having classes, and > objects in the old days, and also did fine in the older days in Assembler > :-D . > So according to this logic, we really should be doing everything in > machine code (as I actually did briefly 24 years ago :-D ), who needs new > features such as those whatmacallit... ohhh yeahh... "compilers" :-D . Well I give you the benefit of the doubt, and believe you. But that does not help me, because I still do not know which case you are talking about.... So for my benefit, please enlighten me with an example. >From your above statement, I take, that you already used closures, and that the big improvements really happened of a result of anonymous methods. Just to be save, let me state the obvious: We are talking of dropping the function name; and introducing the ability, to declare the function anywhere within the code (probably the latter being the important). That are the 2 only things, that anonymous methods do offer? (OR am I missing anything?) If so then I do not see how they save 20000 lines? - The name is part of the declaration line, SO it should not affect the line count at all). Unless you always write the name on a separate line (which I would consider a very special case) - the place of declaration also does not change the line count. > -----Original Message----- From: Martin > Sent: Sunday, March 03, 2013 7:38 PM > To: FPC developers' list > Subject: Re: [fpc-devel] Delphi anonymous methods > > On 04/03/2013 01:47, Boian Mitov wrote: > Really, just by dropping the names? Or did you mean, you did all that by > using closures? > > Closures, do not need to be written/declared in the middle of other code > (in-line)

Reply by email

Alexander Klenin
to Boian Mitov: Here is another even simpler example: AItem := GComponentEditorList.Find( function( AItem…
Boian Mitov wrote 8 lines
Here is another even simpler example: AItem := GComponentEditorList.Find( function( AItem : IComponentEditorItem ) : Boolean begin Result := ( AComponent is AItem.GetInstance().ComponentClass ); end );

Note that with proposed "lambda" syntax this will be even shorter:

AItem := GComponentEditorList.Find(
               lambda TComponentEditorListFilter as
                 AComponent is AItem.GetInstance().ComponentClass;
            );

P. S. Boian, could you please
stop top-posting and splitting your thoughts into so many emails? It will make discussion much easier to follow.

Alexander S. Klenin

Reply by email

Boian Mitov
to Boian Mitov: Here is another even simpler example: AItem := GComponentEditorList.Find( function( AItem…

What people don't usually realize is that an anonymous method indeed is internally expanded to a full blown object of unique class, with member variables and all. Indeed I use the anonymous methods to effectively declare a new class and make instance of it right in place with only couple of lines of code. In most cases anonymous methods effectively eliminate the need to declare new class for certain purpose.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 20 lines
-----Original Message----- From: Boian Mitov Sent: Sunday, March 03, 2013 9:06 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods Here is another even simpler example: AItem := GComponentEditorList.Find( function( AItem : IComponentEditorItem ) : Boolean begin Result := ( AComponent is AItem.GetInstance().ComponentClass ); end ); In this case you will either need additional member class variable (It will increase the memory usage), or you will need to declare a whole class just to achieve what I do with one line of code :-) . Sweet! :-)

Reply by email

Boian Mitov
to Alexander Klenin: Note that with proposed "lambda" syntax this will be even shorter: AItem :=…

Thank you!
I am sorry, got overexcited.
I like the lambda proposal, but on the other hand, I have to use Delphi (at least for now).
The "advantage" of the Delphi implementation is that it uses "familiar" "Pascal like" syntax, but I am sure we can get used to the "lambda" syntax.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 21 lines
-----Original Message----- From: Alexander Klenin Sent: Sunday, March 03, 2013 9:11 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, Mar 4, 2013 at 4:06 PM, Boian Mitov wrote: Note that with proposed "lambda" syntax this will be even shorter: AItem := GComponentEditorList.Find( lambda TComponentEditorListFilter as AComponent is AItem.GetInstance().ComponentClass; ); P. S. Boian, could you please stop top-posting and splitting your thoughts into so many emails? It will make discussion much easier to follow. -- Alexander S. Klenin

Reply by email

Alexander Klenin
to Martin: Really, just by dropping the names? Or did you mean, you did all that by using closures?…
Martin wrote
Closures, do not need to be written/declared in the middle of other code (in-line)

Strictly speaking, they do not. However, if the closures are required to be named,
their expressive power and readability will suffer greatly.

Nevertheless, I agree what the implementation plan can be detailed even further:
1) Anonymous procedures *without* closures -- basically, just another syntax for nested procedures.
This is an important step for several reasons:
1.1) Syntax part is already done in a branch -- so just code clean-up and merge left.
1.2) This would be useful as an optimization even after the full closure support is implemented.
Note that closures introduce significant overhead -- in particular, if I understand correctly,
in Delphi every local variable access becomes a reference to the frame object field,
*even in the parent procedure*. So "nested" anonymous procedures, together with
good inlining support, are crucial for the efficient implementation of, for example,
various "ForEach" methods.
Of course, after closure support is implemented, closures should be somehow distinguished from
nested procedures -- either by additional syntax or via statical code analysis by the optimizer.

2) Named closures support -- while I do think that anonymous procedures are useful,
Martin has a point too -- it feels strange that you *must* use anonymous procedure in order to create a closure.
Perhaps a named nested procedures should be explicitly extendabe to closures too:

  type
    TIntProcRef = reference to procedure (X: Integer);
  function Outer(A, B: Integer): TIntProcRef;
  var
    i, j: Integer;
    procedure Inner1(C: Integer); A := i; end;
    procedure Inner2(D: Integer) closure (var A; i); A := i; end;
  begin
    Result := Inner1; // type error, Inner1 if of type "procedure ... is nested
    Result := Inner2; // ok
  end;
  Note the following details:
  2.0) The exact syntax is, of course, up to debate.
  2.1) Explicit closures allow specify by-value vs by-reference method

of closing over every variable,
2.2) It is possible to even add modifiers like "const" and "out" in the future.
2.3) There should probably be some way to automatically close over all variables used --
for example:

    procedure Inner2(D: Integer) closure (var *); A := i; end; // All

variables by reference

    procedure Inner2(D: Integer) closure (*); A := i; end; // All

variables by value

    procedure Inner2(D: Integer) closure; A := i; end; // By reference

in Delphi mode, by value otherwise ??
again, syntax is debatable
2.4) Conversely, compiler could check that every variable reference inside the closure is specified in the header,
thus avoiding some typical errors.

3) Anonymous closures support -- a combination of the above:
   // Delphi-compatible syntax. Could be made to *not* use closures in
ObjFPC as an optimization.
   // Of course no-closures variant will fail if Apply procedure
stores the reference in a global variable for some reason.
   Apply(AIntArray, function (var AValue: Integer): Integer; begin
Result := a + x; end;)
   // Same as above, but a closure is forced.
  Apply(AIntArray, function (var AValue: Integer): Integer closure(x);
begin Result := a + x; end;)
   // Using "lambda" syntax.
   Apply(AIntArray, lambda TIntIntFunc closure(x) as a + x;)
   // Shortest variant.
   Apply(AIntArray, lambda TIntIntFunc as a + x;)

4) As stated above, either a syntax to explicitly turn off a closure for anonymous procedure,
or intelligent enough optimizer to do that automatically. I have some ideas on both fronts,
but I suggest we first discuss previous points.

Alexander S. Klenin

Reply by email

Boian Mitov
to Alexander Klenin

It may be a good idea to analyze the current Delphi implementation. In essence the anonymous method expands to a class and interface. The interface Execute method has the parameters of the anonymous function. and the corresponding interface has the Execute method. The class contains all the variables that are captured from the current context, and the constructor of the class does the capture. The class is reference counted trough the interface, and is disposed when all references are released.
There are some interesting side effects and benefits from the implementation, and there are fear number of articles about that on the web.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 15 lines
-----Original Message----- From: Alexander Klenin Sent: Sunday, March 03, 2013 9:57 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, Mar 4, 2013 at 2:38 PM, Martin wrote: Nevertheless, I agree what the implementation plan can be detailed even further: 1) Anonymous procedures *without* closures -- basically, just another syntax for nested procedures. This is an important step for several reasons: ....

Reply by email

Michael Fuchs
to Graeme Geldenhuys: Just curious... why must such a feature be allowed in Object Pascal? Referring to the…
Graeme Geldenhuys wrote 12 lines
[...] It was clearly stated in the past that FPC will not support the C/C++ language feature of declaration a variable in-line inside code blocks, but only in var sections. Example of not allowed code: for i: integer = 0 to 10 do begin end; [...] From what I can see, anonymous methods are just like the above code...

No, inside declaration is not anonymous, the declared var has a name.

Look at this:

   with TObject.Create do begin
     WriteLn(ToString);
     Free;
   end;

That is anonymous, and it works in Object-Pascal.

On the other hand I am not sure if anonymous are a good idea, even if I like them while working in VB.NET.
But please: if they are coming, don't implement them in the bad way of Delphi.

Michael

Reply by email

Marco van de Voort
to Graeme Geldenhuys: Just curious... why must such a feature be allowed in Object Pascal? Referring to the…

In our previous episode, Graeme Geldenhuys said:

> > I want to implement support of Delphi anonymous methods for fpc. Just curious... why must such a feature be allowed in Object Pascal?

In Delphi, synchronization primitives like queue() and synchronize() have been adapted to work with them, so they are actually more used than some other new features.

So compatibility wise, it will probably get implemented sooner or later, and better avoid the usual dance of rolling an own, and implementing the compatible later anyway.

Reply by email

Graeme Geldenhuys
to Boian Mitov: Strongly disagree. Anonymous methods are a critical feature of any mother language, and…
Boian Mitov wrote
vast improvements of the code and the readability.

They are unreadable to me.

I recently started rewriting our libraries with anonymous methods and that alone allowed for cutting over 20000 lines of code

Just my dropping method names? I doubt that.

ps:
You do know that the Object Pascal language already supports things like method pointers, so passing methods to a procedure common - plus it has the benefit that the method is well named (so you know what it should be doing).

Anonymous methods seem to be exactly what existing method pointers are, but with the downside that they are obscure (no names to hint to what they do), and defined in the wrong place in code.

If you have never developed with them, (as was I), you never know what you have been missing.

This is what I am trying to find out. So far, with everything I have read and seen. I can do the same thing in code, using method pointers and it will be more structured code (with names and defined in the correct location in my unit]. I simply don't see a need for anonymous methods. Maybe other languages have them, because they didn't have the method pointer construct to start with?

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Graeme Geldenhuys
to Alexander Klenin: On Mon, Mar 4, 2013 at 11:15 AM, Graeme Geldenhuys Because computer science is advancing,…
Alexander Klenin wrote
Because computer science is advancing, and there is a limit after which programming language can not ignore those advancements and stay relevant.

Sure, I understand that. I just haven't seen an example that explains why it is needed. Kind of why I am asking about this now.

Method pointers, which already exist for a long time, seem to allow the same thing (passing methods to other functions etc), and they at least have the benefit that the method is named (hint to the developer what it does), and that it is defined and implemented in a more sane location in the unit.

Was the anonymous method concept implemented in other languages, because they didn't have the method pointer concept that Object Pascal has? If so, does Object Pascal really need another method pointer type implementation?

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Graeme Geldenhuys
to Marco van de Voort: In our previous episode, Graeme Geldenhuys said: In Delphi, synchronization primitives…
Marco van de Voort wrote
In Delphi, synchronization primitives like queue() and synchronize() have been adapted to work with them, so they are actually more used than some other new features.

Sure, just like Delphi implemented Advanced Records, when the Object type already does the exact same thing! Was "advanced records" really needed, NO. Just because Embarcadero starting using there duplicated functionality, doesn't make it good, or better than what existed before. Here is an example

Does the following make sense?

http://docwiki.embarcadero.com/Libraries/XE3//en/System.IOUtils.TDirectory

  TDirectory = record
    ...
    class procedure Blablabla(...)
  end;

HINT:
Proof that Embarcadero lost the plot, when you read "class procedure", but it is defined in a record, and not a class? Also, the TDirectory implementation could just as easily have been defined in a Class with class methods, and the actually usage would have been exactly the same [and made more sense]. Thus no need for the "advanced record" rubbish. It is a duplication of the functionality in a Class and Object type.

Thus, isn't anonymous method just a bad and duplicate implementation of method pointers. Passing methods to functions etc.?

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Graeme Geldenhuys
to Boian Mitov: Here is example: Parallel execution with selection of executor: for i := 0 to…
Boian Mitov wrote
In this case, not only you save declaration, you save the need to write a whole new class just for the task.

All my code live in classes already, so I would simply have benefited by having a properly defined method. Then pass the method pointer to the AExecutionTask.Add(..) call. Your example still doesn't convince me that anonymous methods were needed. In my OOP code, I wouldn't have saved any lines of code.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Schnell
to Graeme Geldenhuys: Sure, just like Delphi implemented Advanced Records, when the Object type already does…
Graeme Geldenhuys wrote
Was "advanced records" really needed, NO.

As discussed in another thread:

It does make sense to allow for a kind of class that does not need to reside on the heap and, (residing on the stack or global space) does not need instantiation to gain memory space.

OTOH, for me it would be more straight forward to do this with a class flavor specification. And on top of this record would be obsolete (but should remain for compatibility) as such a class would be the same as a traditional record when no methods are defined.

(Issue: when assigning, with records the memory is copied, with classes only the pointer. This asks for some ambiguity)

-Michael

Reply by email

Aleksa Todorovic
to Graeme Geldenhuys: They are unreadable to me. Just my dropping method names? I doubt that. ps: You do know…
Graeme Geldenhuys wrote 11 lines
On 2013-03-04 01:47, Boian Mitov wrote: > vast improvements of the code and the readability. They are unreadable to me. > I recently started > rewriting our libraries with anonymous methods and that alone allowed for > cutting over 20000 lines of code Just my dropping method names? I doubt that.

It's not removing method names that cut all those lines, but whole class declarations. Imagine situation where you want to call specific method as callback but you also want to pass some parameters to that method. Your options would be:

- declare callback interface as class, and call specific method in that class (Java-style); you will need to set some fields of callback object with specific parameters
- declare callback interface as method pointer, and call it (similar to previous solution); again, you will need to set some fields of callback objects
- declare callback interface as class or method pointer, and in advance add parameter with type 'array of const' for user-defined parameters; would work, but you would loose type-safety
- declare callback interface as function pointer, and pass closure/anonymous method to it; let the compiler do all the magic, wrap-up local variables for you and "send" appropriate values to specific function call

There are definitely benefits from this feature, but they require different architecture/design of your application.

Regards,
Aleksa

Reply by email

Marco van de Voort
to Graeme Geldenhuys: Sure, just like Delphi implemented Advanced Records, when the Object type already does…

In our previous episode, Graeme Geldenhuys said:

Show quoted text 7 lines
> In Delphi, synchronization primitives like queue() and synchronize() have > been adapted to work with them, so they are actually more used than some > other new features. Sure, just like Delphi implemented Advanced Records, when the Object type already does the exact same thing! Was "advanced records" really needed, NO.

Of course it was. Objects are not a binary dumpable type due to their possible VMT link.

Moreover, from Delphi's case Objects are redundant (keep in mind they haven't supported even the object based libraries like "Objects" since D2 or so. It might even be D1, but I don't know that one that well)

So it makes sense to develop a clean new type, as a start to the deprecation of TP objects (that have lingered as legacy for 17 years).

If I were Embarcadero, I'd do exactly the same.

Keep in mind that our situation is different from Delphi there. We _DO_ support objects because of TV.

Just because Embarcadero starting using there duplicated functionality, doesn't make it good, or better than what existed before.

I never liked the dual nature of TObject.

Show quoted text 10 lines
Here is an example Does the following make sense? http://docwiki.embarcadero.com/Libraries/XE3//en/System.IOUtils.TDirectory TDirectory = record ... class procedure Blablabla(...) end;

That's a totally different discussion. And yes, that is what modern users ask. One can discuss if that is sane, but if you would just open your eyes, and read the maillists (ours too) that are full of comparisons with newer OO centric languages (Python,Java,.NET, then you understand why Embardero does this.

Moreover, IMHO compatibility is not pick what you like. Either you are compatible or not. And I never made a religion out of D7. IMHO D7 is as dirty as the rest in many ways.

So it is either start with a new language/dialect from a pure principle, and apply it everywhere, or be compatible. Mixing it only leads to infinite discussion, slippery slopes etc.

I chose the latter. Compatibility. All the way. No compromise.

Is it pure? No. Is it perfect? No. Is it better than the alternative? Yes.

Currently FPC is much dirtier than Delphi if only because it has two implementations for everything.

Reply by email

Graeme Geldenhuys
to Michael Schnell: As discussed in another thread: It does make sense to allow for a kind of class that does…
Michael Schnell wrote
It does make sense to allow for a kind of class that does not need to reside on the heap and, (residing on the stack or global space)

And that is exactly what the Object type [already] does... and was introduced into the language in Turbo Pascal v5.5 (if I got the version right).

http://www.freepascal.org/docs-html/ref/refse25.html#x61-680005.1

I still use the Object type to this day for performance or ease of use.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Schnell
to Graeme Geldenhuys
Graeme Geldenhuys wrote
I still use the Object type to this day for performance or ease of use.

AFAIK, some of my colleagues do same.

For me the triple choice of a "class", "record" and "object" notation for a type defining a combination of data and associated functions is rather queer. I would prefer using a single keyword (supposedly "class") and be enabled to add a "flavor" choice if I want it in another memory location than on the heap, without necessary use of a constructor and possibly faster.

-Michael

Reply by email

Martin
to Boian Mitov: Here is example: Parallel execution with selection of executor: for i := 0 to…
Boian Mitov wrote 21 lines
Here is example: Parallel execution with selection of executor: for i := 0 to AMaxScaleIndex - 1 do begin APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); AExecutionTask.Add( AExecutor.Execute( procedure() begin ProcessOne( levelScale[ i ], img, hitThreshold, winStride, padding, APerIterationLocations[ i ] ); end )); end; In this case, not only you save declaration, you save the need to write a whole new class just for the task. This code reduced well over 30 lines of code alone. I have a lot of other examples as well ;-) .

Ok, I can see the closure helping, but why the anonymous procedure?

If FPC would offer something like this:

Procedure Foo;
var
   // your locals
      procedure  Bar(); closure;
        begin
          ProcessOne( levelScale[ i ], img, hitThreshold, winStride,
padding, APerIterationLocations[ i ] );
        end
begin
   // your code from above
   for i := 0 to AMaxScaleIndex - 1 do
    begin
    APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() );
    AExecutionTask.Add( AExecutor.Execute( @Bar  ));
end;

I added:
- the name "Bar"
- Used is at reference
- the keyword "closure"

The above code would then create the exact same closure, as your code does. And it does not need an anonymous method.

Of course for portability of Delphi code, in {$mode Delphi} you need the anonymous method.
But the argument on this thread was, that you needed it, because anonymous functions allowed to do things not possible (or very hard) without. And that argument still does not hold up. It only applies to closures.

There is only one other difference between the 2. And that is the subjective preference where you like the code.
- You may find it more readable to see see code of a function in-lined. So you do not need to scroll.
- You may prefer the shorter body of the none anonymous version. After all, if you give it a meaningful name, it should read as easy as the inlined version.
But that is personal preference. It can not be argued on.

Reply by email

Martin
to Boian Mitov: One thing for sure, I probably will very much never need to declare TThread inherited…
Boian Mitov wrote 6 lines
One thing for sure, I probably will very much never need to declare TThread inherited classes. I can use a single anonymous method for that, thanks to the ability of the anonymous method to capture local and member variables. This is something not doable with closure as it has fixed number of parameters ;-) .

Afaik, that is exactly what a closure is. To capture the scope/environment of the surrounding code (including the local variables of the procedure in which it is declared.

An anonymous method just skips the name, and allows to declare it in-line.

Delphi may not offer them individually. I do not know... But this is not about what Delphi offers.

Reply by email

Martin
to Alexander Klenin: Strictly speaking, they do not. However, if the closures are required their expressive…
Alexander Klenin wrote 12 lines
On Mon, Mar 4, 2013 at 2:38 PM, Martin wrote: > Closures, do not need to be written/declared in the middle of other code > (in-line) Strictly speaking, they do not. However, if the closures are required to be named, their expressive power and readability will suffer greatly. Nevertheless, I agree what the implementation plan can be detailed even further: 1) Anonymous procedures *without* closures -- basically, just another syntax for nested procedures.

That might be interested for mode Delphi

2) Named closures support -- while I do think that anonymous procedures are useful,

And this could be in mode FPC too. So "purists" can still enjoy closures. But it keeps one of the thinks that make Pascal: Declaration is all done before the code block starts.

Show quoted text 9 lines
3) Anonymous closures support -- a combination of the above: // Delphi-compatible syntax. Could be made to *not* use closures in 4) As stated above, either a syntax to explicitly turn off a closure for anonymous procedure, or intelligent enough optimizer to do that automatically. I have some ideas on both fronts, but I suggest we first discuss previous points.

IMHO explicit Syntax.

But in the recent light of discussions to keep pascal being Pascal, anonymous functions could be entirely mode delphi only.

From the reasons for anonymous methods.

Show quoted text 7 lines
in Delphi every local variable access becomes a reference to the frame object field, *even in the parent procedure*. So "nested" anonymous procedures, together with good inlining support, are crucial for the efficient implementation of, for example, various "ForEach" methods.

That could be implemented for *named* closures too, and then there was no need for the anonymous.

IMHO anonymous methods are a syntactical difference only. All functionality can be done with named equivalents too.

Reply by email

Martin
to Boian Mitov: It may be a good idea to analyze the current Delphi implementation. In essence the…
Boian Mitov wrote 11 lines
It may be a good idea to analyze the current Delphi implementation. In essence the anonymous method expands to a class and interface. The interface Execute method has the parameters of the anonymous function. and the corresponding interface has the Execute method. The class contains all the variables that are captured from the current context, and the constructor of the class does the capture. The class is reference counted trough the interface, and is disposed when all references are released. There are some interesting side effects and benefits from the implementation, and there are fear number of articles about that on the web.

All fine and good. But all that can be done with a *named* closure too

Reply by email

Alexander Klenin
to Martin
Martin wrote 15 lines
On 04/03/2013 06:06, Boian Mitov wrote: > > It may be a good idea to analyze the current Delphi implementation. > In essence the anonymous method expands to a class and interface. > The interface Execute method has the parameters of the anonymous function. > and the corresponding interface has the Execute method. > The class contains all the variables that are captured from the current > context, and the constructor of the class does the capture. > The class is reference counted trough the interface, and is disposed when > all references are released. > There are some interesting side effects and benefits from the > implementation, and there are fear number of articles about that on the web. All fine and good. But all that can be done with a *named* closure too

Also, Boian, I appreciate your enthusiasm very much, but please read this thread from the start --
the implementation details you mention are extensively described in the documents linked
from the first message.

Alexander S. Klenin

Reply by email

Mattias Gaertner
to Martin: Ok, I can see the closure helping, but why the anonymous procedure? If FPC would offer…
Show quoted text 50 lines
On 04/03/2013 04:54, Boian Mitov wrote: > Here is example: > > Parallel execution with selection of executor: > > for i := 0 to AMaxScaleIndex - 1 do > begin > APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); > AExecutionTask.Add( AExecutor.Execute( > procedure() > begin > ProcessOne( levelScale[ i ], img, hitThreshold, winStride, > padding, APerIterationLocations[ i ] ); > end > )); > > end; > > In this case, not only you save declaration, you save the need to > write a whole new class just for the task. > This code reduced well over 30 lines of code alone. > I have a lot of other examples as well ;-) . Ok, I can see the closure helping, but why the anonymous procedure? If FPC would offer something like this: Procedure Foo; var // your locals procedure Bar(); closure; begin ProcessOne( levelScale[ i ], img, hitThreshold, winStride, padding, APerIterationLocations[ i ] ); end begin // your code from above for i := 0 to AMaxScaleIndex - 1 do begin APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); AExecutionTask.Add( AExecutor.Execute( @Bar )); end; I added: - the name "Bar" - Used is at reference - the keyword "closure" The above code would then create the exact same closure, as your code does. And it does not need an anonymous method.

Nice. Gimme, gimme.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 55 lines
On Mon, 04 Mar 2013 11:17:53 +0000 Martin wrote: > On 04/03/2013 04:54, Boian Mitov wrote: >> Here is example: >> >> Parallel execution with selection of executor: >> >> for i := 0 to AMaxScaleIndex - 1 do >> begin >> APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); >> AExecutionTask.Add( AExecutor.Execute( >> procedure() >> begin >> ProcessOne( levelScale[ i ], img, hitThreshold, winStride, >> padding, APerIterationLocations[ i ] ); >> end >> )); >> >> end; >> >> In this case, not only you save declaration, you save the need to >> write a whole new class just for the task. >> This code reduced well over 30 lines of code alone. >> I have a lot of other examples as well ;-) . > > Ok, I can see the closure helping, but why the anonymous procedure? > > If FPC would offer something like this: > > Procedure Foo; > var > // your locals > procedure Bar(); closure; > begin > ProcessOne( levelScale[ i ], img, hitThreshold, winStride, > padding, APerIterationLocations[ i ] ); > end > begin > // your code from above > for i := 0 to AMaxScaleIndex - 1 do > begin > APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); > AExecutionTask.Add( AExecutor.Execute( @Bar )); > end; > > I added: > - the name "Bar" > - Used is at reference > - the keyword "closure" > > The above code would then create the exact same closure, as your code > does. And it does not need an anonymous method. Nice. Gimme, gimme.

IMHO this is a pefectly acceptable solution.
Adds only a modifier (modifiers are not keywords) and offers all advantages of closures.

No need for 'anonymous' procedures, which are very unpascal-ish. People who want that should not be using Pascal to begin with.

Michael.

Reply by email

Marcos Douglas
to Graeme Geldenhuys: They are unreadable to me. Just my dropping method names? I doubt that. ps: You do know…
Graeme Geldenhuys wrote 31 lines
On 2013-03-04 01:47, Boian Mitov wrote: > vast improvements of the code and the readability. They are unreadable to me. > I recently started > rewriting our libraries with anonymous methods and that alone allowed for > cutting over 20000 lines of code Just my dropping method names? I doubt that. ps: You do know that the Object Pascal language already supports things like method pointers, so passing methods to a procedure common - plus it has the benefit that the method is well named (so you know what it should be doing). Anonymous methods seem to be exactly what existing method pointers are, but with the downside that they are obscure (no names to hint to what they do), and defined in the wrong place in code. > If you have never developed with them, (as was I), you never know what you > have been missing. This is what I am trying to find out. So far, with everything I have read and seen. I can do the same thing in code, using method pointers and it will be more structured code (with names and defined in the correct location in my unit]. I simply don't see a need for anonymous methods. Maybe other languages have them, because they didn't have the method pointer construct to start with?

+1

Marcos Douglas

Reply by email

Sven Barth
to Michael Van Canneyt: IMHO this is a pefectly acceptable solution. Adds only a modifier (modifiers are not…
Michael Van Canneyt wrote 66 lines
On Mon, 4 Mar 2013, Mattias Gaertner wrote: > On Mon, 04 Mar 2013 11:17:53 +0000 > Martin wrote: > >> On 04/03/2013 04:54, Boian Mitov wrote: >>> Here is example: >>> >>> Parallel execution with selection of executor: >>> >>> for i := 0 to AMaxScaleIndex - 1 do >>> begin >>> APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); >>> AExecutionTask.Add( AExecutor.Execute( >>> procedure() >>> begin >>> ProcessOne( levelScale[ i ], img, hitThreshold, winStride, >>> padding, APerIterationLocations[ i ] ); >>> end >>> )); >>> >>> end; >>> >>> In this case, not only you save declaration, you save the need to >>> write a whole new class just for the task. >>> This code reduced well over 30 lines of code alone. >>> I have a lot of other examples as well ;-) . >> >> Ok, I can see the closure helping, but why the anonymous procedure? >> >> If FPC would offer something like this: >> >> Procedure Foo; >> var >> // your locals >> procedure Bar(); closure; >> begin >> ProcessOne( levelScale[ i ], img, hitThreshold, winStride, >> padding, APerIterationLocations[ i ] ); >> end >> begin >> // your code from above >> for i := 0 to AMaxScaleIndex - 1 do >> begin >> APerIterationLocations.Add( >> TRTDynamicList<TVLImageRect>.Create() ); >> AExecutionTask.Add( AExecutor.Execute( @Bar )); >> end; >> >> I added: >> - the name "Bar" >> - Used is at reference >> - the keyword "closure" >> >> The above code would then create the exact same closure, as your code >> does. And it does not need an anonymous method. > > Nice. Gimme, gimme. IMHO this is a pefectly acceptable solution. Adds only a modifier (modifiers are not keywords) and offers all advantages of closures. No need for 'anonymous' procedures, which are very unpascal-ish. People who want that should not be using Pascal to begin with.

If you guys would read what I wrote in one of my first answers to Vasiliy in this thread than you would know that I want him to implement this possiblity as well... but after all, who reads the mails of some strange computer science student who just happens to work on the compiler -.-

To rephrase: implement support for anonymous functions for Delphi compatibility (maybe coupled to a mode switch) and allow for all other modes the assignment of nested functions/procedures to "reference to" procvars instead. Additionally a shortened "lambda syntax" can be added for really simple cases.

Regards,
Sven

Reply by email

Michael Van Canneyt
to Sven Barth
Sven Barth wrote 77 lines
Am 04.03.2013 13:23, schrieb Michael Van Canneyt: > > > On Mon, 4 Mar 2013, Mattias Gaertner wrote: > >> On Mon, 04 Mar 2013 11:17:53 +0000 >> Martin wrote: >> >>> On 04/03/2013 04:54, Boian Mitov wrote: >>>> Here is example: >>>> >>>> Parallel execution with selection of executor: >>>> >>>> for i := 0 to AMaxScaleIndex - 1 do >>>> begin >>>> APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); >>>> AExecutionTask.Add( AExecutor.Execute( >>>> procedure() >>>> begin >>>> ProcessOne( levelScale[ i ], img, hitThreshold, winStride, >>>> padding, APerIterationLocations[ i ] ); >>>> end >>>> )); >>>> >>>> end; >>>> >>>> In this case, not only you save declaration, you save the need to >>>> write a whole new class just for the task. >>>> This code reduced well over 30 lines of code alone. >>>> I have a lot of other examples as well ;-) . >>> >>> Ok, I can see the closure helping, but why the anonymous procedure? >>> >>> If FPC would offer something like this: >>> >>> Procedure Foo; >>> var >>> // your locals >>> procedure Bar(); closure; >>> begin >>> ProcessOne( levelScale[ i ], img, hitThreshold, winStride, >>> padding, APerIterationLocations[ i ] ); >>> end >>> begin >>> // your code from above >>> for i := 0 to AMaxScaleIndex - 1 do >>> begin >>> APerIterationLocations.Add( TRTDynamicList<TVLImageRect>.Create() ); >>> AExecutionTask.Add( AExecutor.Execute( @Bar )); >>> end; >>> >>> I added: >>> - the name "Bar" >>> - Used is at reference >>> - the keyword "closure" >>> >>> The above code would then create the exact same closure, as your code >>> does. And it does not need an anonymous method. >> >> Nice. Gimme, gimme. > > IMHO this is a pefectly acceptable solution. Adds only a modifier > (modifiers are not keywords) and offers all advantages of closures. > > No need for 'anonymous' procedures, which are very unpascal-ish. > People who want that should not be using Pascal to begin with. If you guys would read what I wrote in one of my first answers to Vasiliy in this thread than you would know that I want him to implement this possiblity as well... but after all, who reads the mails of some strange computer science student who just happens to work on the compiler -.- To rephrase: implement support for anonymous functions for Delphi compatibility (maybe coupled to a mode switch) and allow for all other modes the assignment of nested functions/procedures to "reference to" procvars instead. Additionally a shortened "lambda syntax" can be added for really simple cases.

My apologies, I didn't read the whole thread.

But yes, your proposal seems OK.

And the first to use anonymous functions in FPC distributed code, I will personally make him eat his keyboard. Without pepper and salt.

OK. I might hire "Inkasso-Team Moskou" to help with this ;-)

Michael.

Reply by email

Martin
to Sven Barth: If you guys would read what I wrote in one of my first answers to Vasiliy in this thread…
Sven Barth wrote 5 lines
If you guys would read what I wrote in one of my first answers to Vasiliy in this thread than you would know that I want him to implement this possiblity as well... but after all, who reads the mails of some strange computer science student who just happens to work on the compiler -.-

Yes, you did. 2nd message of the thread.

My reply however was to a mail, claiming (or at least to me giving the impression of doing so) the improvements where given by "anonymous method" rather than "closure".
So I wonted to clarify this, and therefore ended up giving this example

To rephrase: implement support for anonymous functions for Delphi compatibility (maybe coupled to a mode switch)

yes: {$mode Delphi}}

and allow for all other modes the assignment of nested functions/procedures to "reference to" procvars instead. Additionally a shortened "lambda syntax" can be added for really simple cases.

Reply by email

Sven Barth
to Graeme Geldenhuys: Just curious... why must such a feature be allowed in Object Pascal? Referring to the…
Graeme Geldenhuys wrote 6 lines
On 2013-03-02 19:03, vrt277 wrote: > I want to implement support of Delphi anonymous methods for fpc. Just curious... why must such a feature be allowed in Object Pascal? Referring to the recent "butchering of the Object Pascal language" thread we had recently in fpc-pascal.

You should not look only at the syntax (after all I'm not a big fan of the syntax either, but I definitely support the feature). Look behind it and see what it provides. The most important concept of anonymous functions is the closure concept. That the function can capture the content of local variables and extend their lifetime past the lifetime of the function where it was originally defined.

E.g. (and please ignore the syntax!)

=== example begin ===

type
   TMyFunc = reference to function(aArg: Integer): String;
function GetFunction: TMyFunc;
var
   someintf: ISomeInterface;
   s: String;
begin
   someintf := TSomeInterfaceImpl.Create;
   s := someintf.GetSomeString;
   Result := function(aArg: Integer): String
                   begin
                      Result := someintf.SomeFunc(aArg) + s;
                   end;
end;
// somewhere else
var
   f: TMyFunc;
begin
   f := GetFunction;
   Writeln(f(42));
end;

=== example end ===

The "s" and the "someintf" will exist until the "f" variable goes out of scope ("reference to" procvars use rerence counting).

Also in the context of threading anonymous methods can be considered a nice alternative. First there is the point of Synchronize:

The way that currently needs to be done with FPC and older Delphi versions:

=== example begin ===

type
   TMyThread = class(TThread)
   private
     fAddText: String;
     procedure AddTextSync;
   protected
     procedure Execute; override;
   end;
procedure TMyThread.AddTextSync;
begin
   // normally one should use an event or something, but we'll just
directly access the GUI here
   fMyForm.Memo.Lines.Add(fAddText);
end;
procedure TMyThread.Execute;
begin
   //...
   fAddText := 'Step 42';
   Synchronize(@AddTextSync);
   //...
end;

=== example end ===

With anonymous functions:

=== example begin ===

type
   TMyThread = class(TThread)
   protected
     procedure Execute; override;
   end;
procedure TMyThread.Execute;
begin
   //...
   Synchronize(
     procedure
     begin
       fMyForm.Memo.Lines.Add('Step 42');
     end;
   );
   //...
end;

=== example end ===

With the proposed lambda syntax from another recent thread:

=== example begin ===

type
   TMyThread = class(TThread)
   protected
     procedure Execute; override;
   end;
procedure TMyThread.Execute;
begin
   //...
   Synchronize(lambda TProc as fMyForm.Memo.Lines.Add('Step 42'));
   //...
end;

=== example end ===

Also the new extensions of the TThread-API brought another nice gimmick:

=== example begin ===

// fire and forget something :)
TThread.CreateAnonymousThread(procedure
   begin
     SomeThingThatShouldBeDoneParallel;
   end
   ).Start;

=== example end ===

Some of the things could be implemented by allowing "is nested" procvars additionally to normal procvars or "of object" procvars (e.g. for TThread.Synchronize and TThread.Queue). But what is not trivially to implement with current features of FPC is the closure aspect. The resulting code would more ugly than even a really fat anonymous function.

Again: I'm not a supporter of the anonynmous function syntax. But I support the semantic behind it. Which is why I wanted to have closures supported through nested functions/procedures in non-Delphi modes. [And I'd also like a lambda syntax for simple cases, e.g. one statement/expression]

Regards,
Sven

Reply by email

Alexander Klenin
to Martin: That might be interested for mode Delphi And this could be in mode FPC too. So "purists"…
Martin wrote 6 lines
Nevertheless, I agree what the implementation plan can be detailed even further: 1) Anonymous procedures *without* closures -- basically, just another syntax for nested procedures. That might be interested for mode Delphi

No, this would be incompatible -- in Delphi, anonymous procedures are the only syntax for closures.
I was proposing the reverse -- do this on objfpc mode only.

Show quoted text 6 lines
2) Named closures support -- while I do think that anonymous procedures are useful, And this could be in mode FPC too. So "purists" can still enjoy closures. But it keeps one of the thinks that make Pascal: Declaration is all done before the code block starts.

Of course, this should only be on mode FPC, since Delphi does not have named closures.

Show quoted text 6 lines
4) As stated above, either a syntax to explicitly turn off a closure for anonymous procedure, or intelligent enough optimizer to do that automatically. I have some ideas on both fronts, but I suggest we first discuss previous points. IMHO explicit Syntax.

This is certainly easiest from implementation POV, but have some smell of premature optimization.

Show quoted text 11 lines
But in the recent light of discussions to keep pascal being Pascal, anonymous functions could be entirely mode delphi only. From the reasons for anonymous methods. in Delphi every local variable access becomes a reference to the frame object field, *even in the parent procedure*. So "nested" anonymous procedures, together with good inlining support, are crucial for the efficient implementation of, for example, various "ForEach" methods.

The efficiency argument was mostly to show that non-closure procedures are useful,
see argument about anonymous procedures below :)

IMHO anonymous methods are a syntactical difference only. All functionality can be done with named equivalents too.

"syntactical difference" is a very broad concept. The whole notion of high-level programming language is one large pile of syntactical differences from machine code.
Compare this to the concept of objects, or structured loops. Both can be implemented by means of "simpler" features, namely records+procedures and
conditional jumps.
The important question is, whether the new syntax adds enough expressive power to justify the complexity it adds to the language? In the case of anonymous methods, my answer is "yes, but only with lambda or similar extension".
Let's revisit a typical example of anonymous functions -- note that this example does NOT use closures
to avoid another confusion:
0) Suppose we have
type

  TVisitor = function (X: Integer): Integer;
  TTree = class
     procedure VisitPreorder(AVis: TVisitor);
  end;
1) Current syntax:
function AddFive(X: Integer): Integer; Result := X + 5; end;
ATree.VisitPreorder(AddFive);
2) Delphi syntax:
ATree.VisitPreorder(function (X: Integer): Integer; Result := X + 5; end;);
3) With "lambda" syntax:
ATree.VisitPreorder(lambda TVisitor; Result := X + 5; end;);
3) With "as" syntax:
ATree.VisitPreorder(function (X: Integer): Integer as X + 5);
4) With both "lambda" and "as" syntax:
ATree.VisitPreorder(lambda TVisitor as X + 5);

Now, my argument is that (2) does indeed have only a marginal advantage over (1),
but (4) is powerful enough to really make functional-style programming practically
useful (as opposed to theoretically possible).
This is similar to how "object" syntax is enough to make object-oriented programming practical, while using "hand-made" VMTs is too cumbersome and error-prone.

Alexander S. Klenin

Reply by email

Graeme Geldenhuys
to Martin: Ok, I can see the closure helping, but why the anonymous procedure? If FPC would offer…
Martin wrote 8 lines
I added: - the name "Bar" - Used is at reference - the keyword "closure" The above code would then create the exact same closure, as your code does. And it does not need an anonymous method.

+1

Much better solution, an in my opinion, much easier to read than anonymous methods. It looks more Pascal-like.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Van Canneyt
to Alexander Klenin: No, this would be incompatible -- in Delphi, anonymous procedures are the only syntax for…
Alexander Klenin wrote 8 lines
4) With both "lambda" and "as" syntax: ATree.VisitPreorder(lambda TVisitor as X + 5); Now, my argument is that (2) does indeed have only a marginal advantage over (1), but (4) is powerful enough to really make functional-style programming practically useful (as opposed to theoretically possible).

Pascal is declarative, not functional.
Trying to import elements from the second into the first is misguided.

There is of course no *technical* reason why you cannot do this.

But you must have some regard for the basic properties and design principles of Pascal.

Otherwise you have no place in a pascal community, but should go and use some other language. Use Javascript, python, whatever suits you best.

I can understand one wants the functionality of closures, but I draw the line at the rape of Pascal syntax people are proposing here.

I play chess. The rules of chess have not evolved in a long time. It doesn't make the game less popular or interesting to those that play it. I dare you to propose a new movement or a new piece, and see how the chess community reacts.

Michael.

Reply by email

Mattias Gaertner
to Michael Van Canneyt
[...] I play chess. The rules of chess have not evolved in a long time. It doesn't make the game less popular or interesting to those that play it.

Actually, yes it does. ;)

I dare you to propose a new movement or a new piece, and see how the chess community reacts.

Mattias

Reply by email

Martin
to Alexander Klenin: No, this would be incompatible -- in Delphi, anonymous procedures are the only syntax for…
Alexander Klenin wrote 11 lines
On Mon, Mar 4, 2013 at 10:34 PM, Martin wrote: >> Nevertheless, I agree what the implementation plan can be detailed even >> further: >> 1) Anonymous procedures *without* closures -- basically, just another >> syntax for nested procedures. > > > That might be interested for mode Delphi No, this would be incompatible -- in Delphi, anonymous procedures are the only syntax for closures. I was proposing the reverse -- do this on objfpc mode only.

My comment was about anonymous part:
- Any anonymous function, for {$mode delphi} only.
- {$mode objfpc} does not need any anonymous for extending anonymous functions in the delphi mode: I have no opinion.

Show quoted text 8 lines
> 2) Named closures support -- while I do think that anonymous > procedures are useful, > > And this could be in mode FPC too. So "purists" can still enjoy closures. > But it keeps one of the thinks that make Pascal: Declaration is all done > before the code block starts. Of course, this should only be on mode FPC, since Delphi does not have named closures.

Yes, but doesnt hurt if it compiles. mode delphi does not need to be artificially restricted.

The efficiency argument was mostly to show that non-closure procedures are useful,

No argoment there. Both have there place

Show quoted text 5 lines
> IMHO anonymous methods are a syntactical difference only. All functionality > can be done with named equivalents too. "syntactical difference" is a very broad concept. The whole notion of high-level programming language is one large pile of syntactical differences from machine code.

I did *not* mean to diminish the importance of the correct syntax. I merely tried to emphasis the point, that this thread is about 2 things:
- anonymous functions: which is mainly adding new syntax. There is little (if any) new functionality added. You still have the same code. Only now you can put it in a different location.
- closures: which add new functionality.

Show quoted text 32 lines
The important question is, whether the new syntax adds enough expressive power to justify the complexity it adds to the language? In the case of anonymous methods, my answer is "yes, but only with lambda or similar extension". Let's revisit a typical example of anonymous functions -- note that this example does NOT use closures to avoid another confusion: 0) Suppose we have type TVisitor = function (X: Integer): Integer; TTree = class procedure VisitPreorder(AVis: TVisitor); end; 1) Current syntax: function AddFive(X: Integer): Integer; Result := X + 5; end; ATree.VisitPreorder(AddFive); 2) Delphi syntax: ATree.VisitPreorder(function (X: Integer): Integer; Result := X + 5; end;); 3) With "lambda" syntax: ATree.VisitPreorder(lambda TVisitor; Result := X + 5; end;); 3) With "as" syntax: ATree.VisitPreorder(function (X: Integer): Integer as X + 5); 4) With both "lambda" and "as" syntax: ATree.VisitPreorder(lambda TVisitor as X + 5); Now, my argument is that (2) does indeed have only a marginal advantage over (1),

IMHO it does not. Except for, currently "AddFive" can not be a nested procedure. If we could use a nested (none closure) procedure here, then I would prefer this.
However I agree, this is subjective preference.

but (4) is powerful enough to really make functional-style programming practically

I can live with that. I find it odd so that "as" is used in the reverse order compared to current use.

Reply by email

Sven Barth
to Martin
Martin wrote 7 lines
> but (4) is powerful enough to really make functional-style programming > practically > I can live with that. I find it odd so that "as" is used in the reverse order compared to current use.

The use of "as" is based on an idea of mine. C# for example has "=>" and Oxygene has "->" which I didn't consider much Pascal like. Also the compiler needs to know the type of the lambda so it can correctly typecheck its code (after all we have no type inference (yet :P )). So "lambda PROCVARTYPE as EXPR/STMT" came as the most "natural" and Pascal like variant.

Regards,
Sven

Reply by email

Alexander Klenin
to Michael Van Canneyt: Pascal is declarative, not functional. Trying to import elements from the second into the…
Michael Van Canneyt wrote
Pascal is declarative,

Please... no, Pascal is not declarative, and we have establised that fact just about two weeks ago.

not functional. Trying to import elements from the second into the first is misguided.

Pascal is also procedural, not object-oriented.
<sarcasm>
Trying to import this new and weird "object" into a nice procedural language is misguided, stupid, and people proposing that should be banned forever from Pascal comminity...
</sarcasm>

There is of course no *technical* reason why you cannot do this. But you must have some regard for the basic properties and design principles of Pascal.

"Basic properties" is a very general notion.
I suggest specific extensions with their associated costs and benefits -- please let's discuss those. What specific disadvantages will, in your opinion, result from implementing this proposal?

you have no place in a pascal community

That was not nice.

I play chess. The rules of chess have not evolved in a long time. It doesn't make the game less popular or interesting to those that play it.

Yes, actually it does exactly that.

I dare you to propose a new movement or a new piece, and see how the chess community reacts.

With enthusiasm. See http://en.wikipedia.org/wiki/Chess_variant

Alexander S. Klenin

Reply by email

Martin
to Sven Barth: The use of "as" is based on an idea of mine. C# for example has "=>" and Oxygene has "->"…
Sven Barth wrote 15 lines
Am 04.03.2013 15:42, schrieb Martin: > >> but (4) is powerful enough to really make functional-style programming >> practically >> > > I can live with that. I find it odd so that "as" is used in the > reverse order compared to current use. The use of "as" is based on an idea of mine. C# for example has "=>" and Oxygene has "->" which I didn't consider much Pascal like. Also the compiler needs to know the type of the lambda so it can correctly typecheck its code (after all we have no type inference (yet :P )). So "lambda PROCVARTYPE as EXPR/STMT" came as the most "natural" and Pascal like variant.

First: Stressing out: I don't like it. But if we must have one, the lambda approach is the best one yet.
Reason: At least the type is declared at a pascal-like location.

I did not note at first, but the al leaves the "Result" away. So X+5 now looks like a statement.
What would happen with

   ATree.VisitPreorder(lambda TVisitor as begin X := min(10,x); X + 5; end);

Reminds me of perl: the last value is the return value.

If you look for the most natural, pascal like (ignoring the part that declaring a function inline, IMHO is not that)

   ATree.VisitPreorder(TVisitor(Result := X + 5);
   ATree.VisitPreorder(TVisitor(begin Result := X + 5; end);

You are type casting the code, into a procedure of the given type.

Reply by email

Alexander Klenin
to Sven Barth: The use of "as" is based on an idea of mine. C# for example has "=>" and Oxygene has "->"…
Sven Barth wrote 5 lines
> The use of "as" is based on an idea of mine. C# for example has "=>" and Oxygene has "->" which I didn't consider much Pascal like. Also the compiler needs to know the type of the lambda so it can correctly typecheck its code (after all we have no type inference (yet :P )). So "lambda PROCVARTYPE as EXPR/STMT" came as the most "natural" and Pascal like variant.

Alternatively, we can consider to use "is" -- it even has precedent in Ada: http://en.wikipedia.org/wiki/Ada_(programming_language)#.22Hello.2C_world.21.22_in_Ada

Alexander S. Klenin

Reply by email

Alexander Klenin
to Martin: First: Stressing out: I don't like it. But if we must have one, the lambda approach is…
Martin wrote
First: Stressing out: I don't like it. But if we must have one, the lambda approach is the best one yet. Reason: At least the type is declared at a pascal-like location.

I certainly agree that it is subjective in the sense that some persons do like it, and other do not.
However my argument is that is an essential language construct, similar to "for" loop, for example.
It is certainly possible to dislike "for" loops, and always use "while" instead. There is even a programming language which explicitly lacks "for" based on that reasoning.
Nevertheless, most programmers use "for" loops, because the value of "syntax sugar" added by it
is enough to out-weight the burden of learning and understanding one more language construct.
Anonymous functions (with good syntax, of course) fall in this category. The world recognized that fact -- rather slowly, to be sure, but remember that "while"s and "for"s
also took decades to be accepted as standard constructs.

Show quoted text 5 lines
I did not note at first, but the al leaves the "Result" away. So X+5 now looks like a statement. What would happen with ATree.VisitPreorder(lambda TVisitor as begin X := min(10,x); X + 5; end); Reminds me of perl: the last value is the return value.

No, my proposal (which was made in the previous thread in this topic) is following (all-caps denotes non-terminal):
1.1) A function of the form

  function NAME(PARAMS): RETURNTYPE; begin Result := EXPRESSION; end;

can be shortened to

  function NAME(PARAMS): RETURNTYPE as EXPRESSION

1.2) A procedure of the form

  procedure NAME(PARAMS); begin STATEMENT; end;

can be shortened to

  procedure NAME(PARAMS) as STATEMENT

1.3) All other cases (i.e. with several statements in the body) must be spelled in full.
2.1) Given types

  TFuncType = function (PARAMS): RETURNTYPE;
  TProcType = procedure (PARAMS);

2.2) the function declaration

  function NAME(PARAMS): RETURNTYPE;

can be shortened to

  lambda NAME: TFuncType;

2.3) the anonymous function declaration

  function (PARAMS): RETURNTYPE;

can be shortened to

  lambda TFuncType;

2.4) Similarly, for procedures:

  lambda NAME: TProcType;
  lambda TProcType;
So, the answer to your question will be:
ATree.VisitPreorder(lambda TVisitor; begin
  X := min(10,x);
  Result := X + 5;
end);

Note that both proposals are totally orthogonal both to each other and to anonymous functions,
and are useful in isolation -- in particular, "lambda" proposal helps with event handlers:
1) It explicitly declares that a given procedure is supposed to be assigned to an event of certain type,
thus increasing readability.
2) It shortens code, especially for a case of many parameters.
3) It allows to add new parameters to event handlers without breaking user code, thus reducing the likehood of ugly solutions like "OnDrawCellEx".

Both "lambda" and "as" keywords are quite debatable, of course.

Show quoted text 7 lines
If you look for the most natural, pascal like (ignoring the part that declaring a function inline, IMHO is not that) ATree.VisitPreorder(TVisitor(Result := X + 5); ATree.VisitPreorder(TVisitor(begin Result := X + 5; end); You are type casting the code, into a procedure of the given type.

There is certainly a merit in that, but it violates another Pascal "basic principle" -- "prefer keywords to symbols". Also, note that you can not omit Result assignment, since ATree.VisitPreorder(TVisitor(X + 5)); is syntactically ambiguous. So it becomes
ATree.VisitPreorder(TVisitor(Result := X + 5));
vs
ATree.VisitPreorder(lambda TVisitor as X + 5);

Finally, I disagree with unbalanced parenthesis -- but that's probably a typo?

Alexander S. Klenin

Reply by email

Sven Barth
to Alexander Klenin: Alternatively, we can consider to use "is" -- it even has precedent in Ada:…
Alexander Klenin wrote 8 lines
On Tue, Mar 5, 2013 at 1:49 AM, Sven Barth wrote: >> The use of "as" is based on an idea of mine. C# for example has "=>" and > Oxygene has "->" which I didn't consider much Pascal like. Also the compiler > needs to know the type of the lambda so it can correctly typecheck its code > (after all we have no type inference (yet :P )). So "lambda PROCVARTYPE as > EXPR/STMT" came as the most "natural" and Pascal like variant. Alternatively, we can consider to use "is" -- it even has precedent in Ada: http://en.wikipedia.org/wiki/Ada_(programming_language)#.22Hello.2C_world.21.22_in_Ada

Would indeed be a nice idea as well :)

Regards,
Sven

Reply by email

Martin
to Alexander Klenin: I certainly agree that it is subjective in the sense that some persons do like it, and…
Alexander Klenin wrote
Anonymous functions (with good syntax, of course) fall in this category. The world recognized that fact -- rather slowly, to be sure, but remember that "while"s and "for"s also took decades to be accepted as standard constructs.

I am not going to ask for proof of this statement (as for example in quotation of literature on the topic).
For the arguments sake, let's assume the above.

Show quoted text 6 lines
No, my proposal (which was made in the previous thread in this topic) is following (all-caps denotes non-terminal): 1.1) A function of the form function NAME(PARAMS): RETURNTYPE; begin Result := EXPRESSION; end; can be shortened to function NAME(PARAMS): RETURNTYPE as EXPRESSION

IMHO that is not a good idea. It adds an additional construct, that every reader must know how to read. It does not add/save enough to be needed.

Show quoted text 9 lines
> If you look for the most natural, pascal like (ignoring the part that > declaring a function inline, IMHO is not that) > > ATree.VisitPreorder(TVisitor(Result := X + 5); > ATree.VisitPreorder(TVisitor(begin Result := X + 5; end); > > You are type casting the code, into a procedure of the given type. There is certainly a merit in that, but it violates another Pascal "basic principle" -- "prefer keywords to symbols".

We could also use the new, have a constructor for everything (TArray.Create) style. Personally, the idea appals me, but

    TVisitor.Create(Result := x + 5)

Another way to avoid the "as"
lambda(TVisitor) .... end

lambda acts as "begin" to the block, so there always must be an end.

Show quoted text 6 lines
Also, note that you can not omit Result assignment, since ATree.VisitPreorder(TVisitor(X + 5)); is syntactically ambiguous. So it becomes ATree.VisitPreorder(TVisitor(Result := X + 5)); vs ATree.VisitPreorder(lambda TVisitor as X + 5);
See above. The omission "of Result :=" is IMHO not desirable.
Finally, I disagree with unbalanced parenthesis -- but that's probably a typo?

yes

Reply by email

Martin
to Alexander Klenin: I certainly agree that it is subjective in the sense that some persons do like it, and…
Alexander Klenin wrote
Both "lambda" and "as" keywords are quite debatable, of course.

IMHO the existing procedure/function keywords should be kept. But with the requirement of using a defined type

Foo(  function as TVisitor; Result := x+5 end; );
or
Foo(  function as TVisitor; begin Result := x+5 end; );
Foo(  function of TVisitor; begin Result := x+5 end; );
or even
Foo(  function TVisitor( Result := x+5 )    );

or anything alike

Reply by email

Boian Mitov
to Martin: All fine and good. But all that can be done with a *named* closure too

Ye, by writing 20 times more code for the same.
What here I can do with 3 lines, otherwise needs declaration of a new class, new interface and new instance of the class.
So what I can do here i 15 seconds would take me 1 hour to do traditionally.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 9 lines
-----Original Message----- From: Martin Sent: Monday, March 04, 2013 3:35 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On 04/03/2013 06:06, Boian Mitov wrote: All fine and good. But all that can be done with a *named* closure too

Reply by email

Boian Mitov
to Michael Van Canneyt: IMHO this is a pefectly acceptable solution. Adds only a modifier (modifiers are not…

Thank you Michael,

This is a good advise :-) .
I guess I really should stop using Delphi in the future :-) . I am surely not using FPC and staying with Delphi for now, but I appreciate your advise.
Having less people use the language is the way to go :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 15 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 4:23 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods IMHO this is a pefectly acceptable solution. Adds only a modifier (modifiers are not keywords) and offers all advantages of closures. No need for 'anonymous' procedures, which are very unpascal-ish. People who want that should not be using Pascal to begin with. Michael.

Reply by email

Michael Van Canneyt
to Boian Mitov: Ye, by writing 20 times more code for the same. What here I can do with 3 lines,…
Boian Mitov wrote
Ye, by writing 20 times more code for the same. What here I can do with 3 lines, otherwise needs declaration of a new class, new interface and new instance of the class. So what I can do here i 15 seconds would take me 1 hour to do traditionally.

This is not correct.

For anonymous functions you do not need to declare a new class. Just name a local method.
That means move a line, and put a name in front of it. No more, no less.

Michael.

Reply by email

Michael Van Canneyt
to Boian Mitov: This is a good advise :-) . I guess I really should stop using Delphi in the future :-) .…
Boian Mitov wrote 7 lines
Thank you Michael, This is a good advise :-) . I guess I really should stop using Delphi in the future :-) . I am surely not using FPC and staying with Delphi for now, but I appreciate your advise. Having less people use the language is the way to go :-D .

If you want to drop FPC for because it forces you to move a line and have to type a name in front of it, then yes, I think you are not on your place working with pascal.

You should then move to C or Javascript, it will dramatically improve the number of characters you must type.

No one argues about the concept of closure.

We do not want you to have to declare N classes and M methods to be able to use it.

We do argue about how this can be implemented in a way that has some regard for the fundamentals of pascal: verbosity, and the requirement to declare everything before you use it.

A local nested, named procedure has been part of Pascal since very long time. The proposal just enhances that idea.

Michael.

Reply by email

Boian Mitov
to Michael Van Canneyt: This is not correct. For anonymous functions you do not need to declare a new class. Just…

I actually somewhat agree with that, except it is less readable since you can't follow the code flow in place but have to scroll up to see what will happen (in for each as example.)
Other than being more difficult to read it is otherwise the same. If you can also pass pointers to it that exist after the function is exited, then it is virtually equivalent.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 17 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 9:03 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, 4 Mar 2013, Boian Mitov wrote: This is not correct. For anonymous functions you do not need to declare a new class. Just name a local method. That means move a line, and put a name in front of it. No more, no less. Michael.

Reply by email

Boian Mitov
to Michael Van Canneyt: IMHO this is a pefectly acceptable solution. Adds only a modifier (modifiers are not…

Actually you are right indeed. I would spill a secret now. I have actually been working on a new language for a while, although it indeed will not only have anonymous methods, but will not have methods altogether, since it is a non procedural and non functional language, and can't even be called "programming" language, but that is a different story ;-) . I am really bound of the limitations of the existing languages, and need to find a drastic solution to progress further ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 7 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 4:23 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods People who want that should not be using Pascal to begin with.

Reply by email

Michael Van Canneyt
to Boian Mitov: I actually somewhat agree with that, except it is less readable since you can't follow…
Boian Mitov wrote
I actually somewhat agree with that, except it is less readable since you can't follow the code flow in place but have to scroll up to see what will happen (in for each as example.)

If you do proper top-down programming, usually there is no need to go and look.

If I see

     if F.NeedUnitTest then
       CreatePropertyUnitTest(Strings,CN,F);

then I know what CreatePropertyUnitTest does, I can follow the logic. Most of the time, I do not need to know the details.

Michael.

Reply by email

Michael Van Canneyt
to Boian Mitov: Actually you are right indeed. I would spill a secret now. I have actually been working…
Boian Mitov wrote 7 lines
Actually you are right indeed. I would spill a secret now. I have actually been working on a new language for a while, although it indeed will not only have anonymous methods, but will not have methods altogether, since it is a non procedural and non functional language, and can't even be called "programming" language, but that is a different story ;-) . I am really bound of the limitations of the existing languages, and need to find a drastic solution to progress further ;-) .

There is a course in witchcraft here in the neighbourhood, shall I send you the details so you can inscribe ? Sounds like just the thing :-)

Michael.

Reply by email

Boian Mitov
to Michael Van Canneyt

No need Michael,

Thank you :-) .
I am actually a master in it, as you can probably guess from our products :-D .
Indeed this new language is a "witchcraft", since it will not even have classes, structures, or even statements :-D .
It is a totally new concept ;-) . But it will take few years to develop. I have hired couple of developers to do some of the initial work. We will see how it will go ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 12 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 9:19 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods There is a course in witchcraft here in the neighbourhood, shall I send you the details so you can inscribe ? Sounds like just the thing :-) Michael.

Reply by email

Boian Mitov
to Michael Van Canneyt: If you want to drop FPC for because it forces you to move a line and have to type a name…

Hi Michael,

Thank you!
I actually have more experience in C++ than in Delphi. I have been using Delphi only for ~15 years, where my active C++ experience dates back to 1990, and I actively develop in C++ and C# on daily basis as well (All of our products support C++ and C#).
I have made some attempts in the past to support Lazarus, and offer our products for it, but due to vast number of bugs and limitations in it, I have all but given up.
I still hope that one day I may offer our components to the lazars/FPC community, but that seems to be just a fantasy :-D . I am actually dropping support for FPC in the latest OpenWire implementation again due to incompatibilities and lack of Delphi features (in this case attributes). It is ok, I don't use Lazarus (spare a brief attempt few years ago to port the libraries), and I probably will never use it, especially after your recommendation :-) , nor will probably most of my customers, and there are fear number of them ;-) .
I have recently started to remove the {$IFDEF FPC} parts from the source code, since the chance to port to FPC seems less and less possible.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 9 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 9:11 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods If you want to drop FPC for because it forces you to move a line and have to type a name in front of it, then yes, I think you are not on your place working with pascal.

Reply by email

waldo kitty
to Vasiliy Kevroletin: I was wrong. Local variables of anonymous function located where they should be: on stack.
Show quoted text 8 lines
It is as I thought about closures before. But this is useless without capturing of variables by value. During creation of anonymous method you *can not bind any values* to it. Anonymous method have only references to captured variables. Pascal don't allows to create static variables inside function like in c-like languages. So you also not able to create unique static variable which available only to one instance of same anonymous method. Even if implementation will create many separate objects for one anonymous function then all instances will be equivalent. Because all instances will refer to same data.

i'm trying to understand what you mean by

Pascal don't allows to create static variables inside function like in c-like languages.

i've done something that i think is what you speak of but it was in Borland's Turbo Pascal... at least TP6... i don't remember how we did it though and can't find any sample code in my library :(

what happened is that the value did not get cleared between invocations of the routine and subsequent executions could use the value already stored... this breaks, of course, if the memory area for the routine is cleared first...

Reply by email

Michael Van Canneyt
to Boian Mitov: Thank you! I actually have more experience in C++ than in Delphi. I have been using…
Boian Mitov wrote 14 lines
Hi Michael, Thank you! I actually have more experience in C++ than in Delphi. I have been using Delphi only for ~15 years, where my active C++ experience dates back to 1990, and I actively develop in C++ and C# on daily basis as well (All of our products support C++ and C#). I have made some attempts in the past to support Lazarus, and offer our products for it, but due to vast number of bugs and limitations in it, I have all but given up. I still hope that one day I may offer our components to the lazars/FPC community, but that seems to be just a fantasy :-D . I am actually dropping support for FPC in the latest OpenWire implementation again due to incompatibilities and lack of Delphi features (in this case attributes).

Attributes have been developed, but are not yet in trunk.

It is ok, I don't use Lazarus (spare a brief attempt few years ago to port the libraries), and I probably will never use it, especially after your recommendation :-) , nor will probably most of my customers, and there are fear number of them ;-) .

I honestly regret this.

But I seriously doubt that this has to do with missing anonymous functions in a delphi-compatible form.

I also doubt that adding anonymous functions would make you change your mind.

Michael.

Reply by email

Alexander Klenin
to Martin: I am not going to ask for proof of this statement (as for example in quotation of…
Martin wrote 8 lines
On 04/03/2013 16:05, Alexander Klenin wrote: > > Anonymous functions (with good syntax, of course) fall in this category. > The world recognized that fact -- rather slowly, to be sure, but > remember that "while"s and "for"s > also took decades to be accepted as standard constructs. I am not going to ask for proof of this statement

I've made two statements here:
1) Anonymous functions are considered essential part of any modern programming language.
For a proof, look at any modern programming language :) Or, to save time, here is a list:
http://en.wikipedia.org/wiki/Anonymous_function#List_of_languages
2) "while" loop took a long time to be invented and widely accepted. First high-level programming languages, like FORTRAN and COBOL, created in 1950s,
did not have it. First more-or-less widely known language to support Algol, which came about 1960.
However, Algol did not became used in practice, and the notion of structured programming was widely debated until the 1970s. For example, FORTRAN 77 still did not have "while" loop, it was considered an extension implemented by some compilers, and it was a standard recommendation to rewrite "while" using "if" and "goto" to increase code portability.
So it took about 10 to 20 years for "while" loops to emerge and become commonplace.
I must note that the part of my statement about "for" is totally wrong -- I just typed without thinking. Of course, FORTRAN had "DO" loops right from the beginning.

> function NAME(PARAMS): RETURNTYPE as EXPRESSION IMHO that is not a good idea. It adds an additional construct, that every reader must know how to read. It does not add/save enough to be needed.

I agree, it is borderline, and needs to be additionally justified. I believe that for each feature, there is a threshold for the baroqueness of syntax required to use it which separates "obscure" from "simple and understandable".
The main barrier for understanding code is not actually the number of language constructs involved -- they are way too few compared to, say, number of procedures in any non-trivial library. The main barrier is the amount of effort required to see the programmers intent while looking at a given piece of code.
For example (still using "lambda" syntax here to not muddle the issue, I'll discuss your alternatives to "lambda" below):

// Task: Select five largest even numbers from the array:
// (0) Theoretically possible with type inference:
AIntArray.Filter(lambda X div 2 = 0).Sort(lambda X > Y).Take(5);
// (1) My proposal
AIntArray.Filter(lambda TIntFilter as X div 2 = 0).Sort(lambda TIntCmp
as X > Y).Take(5);
// (2) Without "as"
AIntArray.
  Filter(lambda TIntFilter; begin Result := X div 2 = 0 end).
  Sort(lambda TIntCmpl; begin Result := X > Y; end).Take(5);
// (3) Without "lambda"
AIntArray.
  Filter(function (X: Integer): Boolean; begin Result := X div 2 = 0 end).
  Sort(function (X, Y: Integer): Boolean; begin Result := X > Y; end).Take(5);
// (4) Without anonymous functions:
function IsEven(X: Integer): Boolean; begin
  Result := X div 2 = 0;
end;
function IsGreaterThan(X, Y: Integer): Boolean; begin
  Result := X > Y;
end;
// ... possibly a lot of code here
AIntArray.Filter(@IsEven).Sort(@IsGreaterThan).Take(5);

As you can see, there is a spectrum of expressive power vs language simplicity. It is debatable at which position of the spectrum Pascal should be, but my opinion is that (4) is way too weak, (0) is probably too strong, and (1) is easier to read then (2), (3) or (4) for any reasonably literate programmer,
regardless of whether or not he knows about details of anonymous functions in Pascal.

We could also use the new, have a constructor for everything (TArray.Create) style. Personally, the idea appals me, but TVisitor.Create(Result := x + 5)

I actually dislike this syntax even for arrays.
Nevertheless, I agree that this could be good idea, except it works only for anonymous functions, thus losing the advantages for named ones.

Another way to avoid the "as" lambda(TVisitor) .... end lambda acts as "begin" to the block, so there always must be an end.

Why not also omit "end" then? Just say that "lambda" must be followed by a single statement,
then for the case of many statements, "begin..end" should be used like in normal blocks.
The only problem is with local declarations, but I guess it is possible to disambiguate
based on "var", "const" and "type" keywords appearing after "lambda". My intention with the designated "as" keyword is to reduce the need for look-ahead
in a grammar (which, btw, can also be considered one of "Pascal principles"). But certainly, is the "as" keyword can always be inferred from context, then I am all for omitting it.

See above. The omission "of Result :=" is IMHO not desirable.

Are you sure? Note that *any* useful single-statement function will start exactly like this
(strictly speaking, it could be also be call to "exit", but obviously it makes no difference).
And single-statement functions are the most important use case for anonymous functions --
basically, if it takes several lines of code anyway, then in might as well be a named function.

Show quoted text 5 lines
IMHO the existing procedure/function keywords should be kept. But with the requirement of using a defined type Foo( function as TVisitor; Result := x+5 end; ); Foo( function as TVisitor; begin Result := x+5 end; ); Foo( function of TVisitor; begin Result := x+5 end; ); Foo( function TVisitor( Result := x+5 ) );

Yes, this could work too, and it does extend well to named functions/procedures:

procedure TForm1.Grid1OnDrawCell as TGridOnDrawCell;
begin
  ...
end;
However, for shortened syntax, I'd prefer single-statement-body
interpretation I described above:
  Foo(function as TVisitor; Result := x+5); // one statement
  Foo(function as TVisitor; begin x *= 2; Result := x+5; end); //
several statements
or, with "Result := " omission
  Foo(function as TVisitor; x+5);
Alexander S. Klenin

Reply by email

Boian Mitov
to Michael Van Canneyt: Attributes have been developed, but are not yet in trunk. I honestly regret this. But I…

Then why do you think I am wasting my time writing all this? I really want to support Lazarus, but that is not even remotely possible today.
I have well over 4 mln. lines of code and I need to support Delphi and C++ Builder with it.
I will surely not abandon my current customer base just to rewrite everything for Lazarus only, and since Lazarus does not support DLL based packages, I will have to stop supporting my C++ and .NET customers as well. In essence I will have to kill my business just to support Lazarus. That would be foolish business decision, both for me and my employees, and customers.
However if ever Lazarus gets attributes, extended RTTI, anonymous methods and dynamic packages at least in Windows, then I surely will invest more time and money in it (I spent a lot of time and money on it few years ago, before giving up.). I know how to take a risk, but I also know when it is foolish to take the risk.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 16 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 11:12 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, 4 Mar 2013, Boian Mitov wrote: But I seriously doubt that this has to do with missing anonymous functions in a delphi-compatible form. I also doubt that adding anonymous functions would make you change your mind.

Reply by email

Howard Page-Clark
to waldo kitty: i'm trying to understand what you mean by i've done something that i think is what you…
waldo kitty wrote 9 lines
i'm trying to understand what you mean by > Pascal don't allows to create static variables inside function like in c-like > languages. i've done something that i think is what you speak of but it was in Borland's Turbo Pascal... at least TP6... i don't remember how we did it though and can't find any sample code in my library :(

You can simulate this in FPC as well as TP by using a local typed constant. e.g.

function GetValue: integer;
const value: integer = 0;
begin
   Inc(value);
   Result:= value;
end;

Successive calls to GetValue() will return 1, 2, 3 etc.

Reply by email

Michael Van Canneyt
to Boian Mitov: Then why do you think I am wasting my time writing all this? I really want to support…
Boian Mitov wrote
Then why do you think I am wasting my time writing all this?

I should be asking this to you :-)

I really want to support Lazarus, but that is not even remotely possible today.

That says it all.

Delphi doesn't support these 'new features' that long either, and you admit working for 15 years with Delphi. So at some point you made a decision to start using new features. Most likely, it was not necessary to use them. It may have made some things easier. Maybe you wanted to support some C# stuff - I do not know the reasons.

In each case, that is when you took the decision not to support Lazarus/FPC, which did not have these features, and which never promised to have them.

And it is also why I do not think that adding these features today will change your decision. Because it is this today, that tomorrow. We are playing catch-up forever anyway.

Do not get me wrong, I do not ask you to change your decision or your code. You have a business to run, and this should be your primary concern.

Michael.

Reply by email

Martin
to Alexander Klenin: I've made two statements here: 1) Anonymous functions are considered essential part of…
Alexander Klenin wrote 19 lines
>> function NAME(PARAMS): RETURNTYPE as EXPRESSION > IMHO that is not a good idea. It adds an additional construct, that every > reader must know how to read. It does not add/save enough to be needed. I agree, it is borderline, and needs to be additionally justified. I believe that for each feature, there is a threshold for the baroqueness of syntax required to use it which separates "obscure" from "simple and understandable". The main barrier for understanding code is not actually the number of language constructs involved -- they are way too few compared to, say, number of procedures in any non-trivial library. The main barrier is the amount of effort required to see the programmers intent while looking at a given piece of code. For example (still using "lambda" syntax here to not muddle the issue, I'll discuss your alternatives to "lambda" below): // Task: Select five largest even numbers from the array: // (0) Theoretically possible with type inference: AIntArray.Filter(lambda X div 2 = 0).Sort(lambda X > Y).Take(5);

How is that possible? In "lambda X > Y " how does the compiler know, if X or Y is the first param?

// (1) My proposal AIntArray.Filter(lambda TIntFilter as X div 2 = 0).Sort(lambda TIntCmp as X > Y).Take(5);

And that is a good example *against* anonymous functions. Even with some c# background (and it does remind me of it / maybe general dotNet), I had to read it several times.
Sure, if it was highlighted it might be easier to find the keywords lambda/as and to know where the expression (the truncated "result :=" statement starts.

// (2) Without "as" AIntArray. Filter(lambda TIntFilter; begin Result := X div 2 = 0 end). Sort(lambda TIntCmpl; begin Result := X > Y; end).Take(5);

You comparison is tainted. the begin/end are not needed. Though, I actually would like them required. Well at least the end. The lambda might serve as the opening.

AIntArray.
   Filter(lambda TIntFilter; Result := X div 2 = 0 end).
   Sort(lambda TIntCmpl; Result := X > Y; end).Take(5);

And that is of course because of your preference for keyword over typecast. Though you are right, even in a typecast a keyword would be good to indicate this code is not executed right away.

   AIntArray.
   Filter(TIntFilter(lambda Result := X div 2 = 0 end).
   Sort(TIntCmpl(lambda Result := X > Y end).Take(5);

Then a none type casted lambda could return a "procedure();", no params, no result.

Show quoted text 9 lines
// (4) Without anonymous functions: function IsEven(X: Integer): Boolean; begin Result := X div 2 = 0; end; function IsGreaterThan(X, Y: Integer): Boolean; begin Result := X > Y; end; // ... possibly a lot of code here AIntArray.Filter(@IsEven).Sort(@IsGreaterThan).Take(5);

And the actual fitter/sort line is so much easier to read. Really, so much easier...

Show quoted text 5 lines
As you can see, there is a spectrum of expressive power vs language simplicity. It is debatable at which position of the spectrum Pascal should be, but my opinion is that (4) is way too weak, (0) is probably too strong, and (1) is easier to read then (2), (3) or (4) for any reasonably literate programmer,

actually from a point of readability

      TIntCmpl(lambda Result := X > Y end

looks easiest to me. WIthin the typecast, you have only an opening /closing keyword. The rest is the code. No distraction

> We could also use the new, have a constructor for everything (TArray.Create) > style. Personally, the idea appals me, but > TVisitor.Create(Result := x + 5) I actually dislike this syntax even for arrays.

As I said: the idea appals me

Show quoted text 5 lines
> Another way to avoid the "as" > lambda(TVisitor) .... end > lambda acts as "begin" to the block, so there always must be an end. Why not also omit "end" then? Just say that "lambda" must be followed by a single statement,

No Pascal is verbose. It must be a proper block. TO easy to misread otherwise.
It does not have to finish with end, there could be another keyword. (Like in repeat until pair).

If there is no block
Foo(lambda TFunc x = a, lambda TFunc y<b)
versus
Foo(lambda TFunc x = a(lambda TFunc y<b))

And if (another of those I personally do not like it) tuples will come, then
Foo(lambda TFunc x = (a, lambda TFunc y<b))
where x is a tuple, and the bracket is too.

I want a none return ticket to a different planet.

Show quoted text 5 lines
then for the case of many statements, "begin..end" should be used like in normal blocks. The only problem is with local declarations, but I guess it is possible to disambiguate based on "var", "const" and "type" keywords appearing after "lambda".

Argh yes, I hadn't thougt of that yet.

Well then that just makes it an even bigger monstrosity. I am not going to think about that now. To much work for something that I do not want in first....

Show quoted text 10 lines
> See above. The omission "of Result :=" is IMHO not desirable. Are you sure? Note that *any* useful single-statement function will start exactly like this (strictly speaking, it could be also be call to "exit", but obviously it makes no difference). And single-statement functions are the most important use case for anonymous functions -- basically, if it takes several lines of code anyway, then in might as well be a named function.

Yes. I used them plenty in perl. But this is pascal. Not perl.

Show quoted text 8 lines
> IMHO the existing procedure/function keywords should be kept. But with the requirement of using a defined type > Foo( function as TVisitor; Result := x+5 end; ); > Foo( function as TVisitor; begin Result := x+5 end; ); > Foo( function of TVisitor; begin Result := x+5 end; ); > Foo( function TVisitor( Result := x+5 ) ); Yes, this could work too, and it does extend well to named functions/procedures: procedure TForm1.Grid1OnDrawCell as TGridOnDrawCell;

we need to find a better substitute for "as"
using, like, of,

procedure TForm1.Grid1OnDrawCell prototype(TGridOnDrawCell); // brackets are optional, but seem better

Reply by email

Boian Mitov
to Michael Van Canneyt: I should be asking this to you :-) That says it all. Delphi doesn't support these 'new…

Correct :-) .
Now back to running it ;-) .
Cheers!
See what I am cooking next:

http://www.mitov.com/OpenWireIDE.zip

Enjoy! :-D

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 12 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 12:41 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, 4 Mar 2013, Boian Mitov wrote: Do not get me wrong, I do not ask you to change your decision or your code. You have a business to run, and this should be your primary concern.

Reply by email

Michael Van Canneyt
to Boian Mitov
Boian Mitov wrote 6 lines
Correct :-) . Now back to running it ;-) . Cheers! See what I am cooking next: http://www.mitov.com/OpenWireIDE.zip

home: >wine OpenWireIDE.exe
p11-kit: couldn't load module: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: No such file or directory p11-kit: couldn't load module: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: No such file or directory fixme:storage:create_storagefile Storage share mode not implemented. err:mscoree:LoadLibraryShim error reading registry key for installroot err:mscoree:LoadLibraryShim error reading registry key for installroot err:mscoree:LoadLibraryShim error reading registry key for installroot err:mscoree:LoadLibraryShim error reading registry key for installroot err:mscoree:LoadLibraryShim error reading registry key for installroot err:mscoree:LoadLibraryShim error reading registry key for installroot fixme:iphlpapi:NotifyAddrChange (Handle 0xebe8cc, overlapped 0xebe8b0): stub p11-kit: couldn't load module: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: No such file or directory wine: configuration in '/home/michael/.wine' has been updated. p11-kit: couldn't load module: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: /usr/lib/i386-linux-gnu/pkcs11/gnome-keyring-pkcs11.so: cannot open shared object file: No such file or directory fixme:process:GetLogicalProcessorInformation ((nil),0x32fde4): stub fixme:gdiplus:GdipSetPathGradientSurroundColorsWithCount not implemented ^Z

:(

Michael.

Reply by email

Martin
to Alexander Klenin: I've made two statements here: 1) Anonymous functions are considered essential part of…
Alexander Klenin wrote
> See above. The omission "of Result :=" is IMHO not desirable. Are you sure? Note that *any* useful single-statement function will start exactly like this
If a = x then Result := 4 else Result := 5;

Single statement, but starts different. And is useful.

But that isn't why I replied again.

Reading the shortened version versus the full anonymous procedure (with var, const, type....) and I realized, that thi's a 2 entirely different things.

The above is NOT an anonymous function. It is a reference to a term. I am not voting for it, but IF it was done, then it should have its own keyword.

It would not allow for var, type or anything (and it will only work for functions, not procedures.)
a.sort(LambdaTerm TMyCompare do x > y)
or
a.sort(TermRef TMyCompare(x > y) )

anonymous function, then would *always* require
a. sort( Function; prototype TMyCompare; [var ...] begin ... end )

the protopybe (modifier) could work for named procedures too. (THey would be required NOT to have any params)

   Function Foo; prototype TMyCompare;
   [var ...]
   begin ... end

Reply by email

Roberto P.
to Boian Mitov: Correct :-) . Now back to running it ;-) . Cheers! See what I am cooking next:…

FPC is really an exciting and always improving language/project, but IMHO if you stretch out too much from the Pascal origin and "general frame", then people will eventually get lost and abandone it.

By the way, given your tastes, you might want to have a look a the D language.
It's my favorite second choice :-)

R#

2013/3/4 Boian Mitov

Show quoted text 31 lines
Correct :-) . Now back to running it ;-) . Cheers! See what I am cooking next: http://www.mitov.com/**OpenWireIDE.zip<http://www.mitov.com/OpenWireIDE.zip> Enjoy! :-D With best regards, Boian Mitov ------------------------------**------------------------- Mitov Software www.mitov.com ------------------------------**------------------------- -----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 12:41 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods On Mon, 4 Mar 2013, Boian Mitov wrote: Do not get me wrong, I do not ask you to change your decision or your code. You have a business to run, and this should be your primary concern. ______________________________**_________________ fpc-devel maillist - http://lists.freepascal.org/**mailman/listinfo/fpc-devel<http://lists.freepascal.org/mailman/listinfo/fpc-devel>

Reply by email

Sven Barth
to Martin: If a = x then Result := 4 else Result := 5; Single statement, but starts different. And…
"Martin" wrote 15 lines
On 04/03/2013 19:16, Alexander Klenin wrote: >> >> See above. The omission "of Result :=" is IMHO not desirable. > > Are you sure? Note that *any* useful single-statement function will > start exactly like this If a = x then Result := 4 else Result := 5; Single statement, but starts different. And is useful. But that isn't why I replied again. Reading the shortened version versus the full anonymous procedure (with

var, const, type....) and I realized, that thi's a 2 entirely different things.

The above is NOT an anonymous function. It is a reference to a term. I am not voting for it, but IF it was done, then it should have its own

keyword.

It would not allow for var, type or anything (and it will only work for

functions, not procedures.)

a.sort(LambdaTerm TMyCompare do x > y) or a.sort(TermRef TMyCompare(x > y) )

This is basically what my idea behind the lambs syntax was: only one expression or statement and no variable, type or constant declarations. And for more complex use case there are either Delphi's anonymous functions or FPC's nested procedures/functions.

anonymous function, then would *always* require a. sort( Function; prototype TMyCompare; [var ...] begin ... end ) the protopybe (modifier) could work for named procedures too. (THey would

be required NOT to have any params)

Function Foo; prototype TMyCompare; [var ...] begin ... end

Ah! Now with the named example I understand the use of the ";" after the "function"...

Regards,
Sven

Reply by email

Sven Barth
to Roberto P.: FPC is really an exciting and always improving language/project, but IMHO if you stretch…
"Roberto P." wrote
FPC is really an exciting and always improving language/project, but IMHO

if you stretch out too much from the Pascal origin and "general frame", then people will eventually get lost and abandone it.

We'll implement features of Delphi anyway for compatibility. So why not use the implementation of it, provide some nice Pascal-style syntax for it and allow FPC users to usr the feature in non-Delphi modes as well. :)

Regards,
Sven

Reply by email

Boian Mitov
to Roberto P.: FPC is really an exciting and always improving language/project, but IMHO if you stretch…

I actually looked at it few years ago. I also bought one of the Digital Mars CDs and still have it. It was at the time garbage collected, and this is a major No No in my book ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 11 lines
From: Roberto P. Sent: Monday, March 04, 2013 2:06 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods FPC is really an exciting and always improving language/project, but IMHO if you stretch out too much from the Pascal origin and "general frame", then people will eventually get lost and abandone it. By the way, given your tastes, you might want to have a look a the D language. It's my favorite second choice :-) R#

Reply by email

Boian Mitov
to Sven Barth: if you stretch out too much from the Pascal origin and "general frame", then people will…

Cool :-).
BTW: When you implement it, please consider making it available for attributes! The Delphi version really sucks in this :-( .
I have not been able to do things like:

[TComponentDialog(
    procedure( AInstance : TComponent)
    begin
       TMyComponnt( AInstance ).ShowDialog();
    end
]
TMyComponnt = class( TComponent )
public
  procedure ShowDialog();
end;

This could have eliminated a full source file, and replaced it with 3 lines :-( . I really hate the half baked attribute and anonymous methods in Delphi :-( .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 6 lines
From: Sven Barth Sent: Monday, March 04, 2013 2:19 PM To: Subject: Re: [fpc-devel] Delphi anonymous methods We'll implement features of Delphi anyway for compatibility. So why not use the implementation of it, provide some nice Pascal-style syntax for it and allow FPC users to usr the feature in non-Delphi modes as well. :)

Reply by email

Boian Mitov
to Michael Van Canneyt: home: >wine OpenWireIDE.exe p11-kit: couldn't load module:…

I have never attempted to use it in wine.
It is at current for Windows only, and is a prerelease. Here are however couple of very old snapshots. They are ~2 months old and miss a lot of new features, but will give you idea.

http://www.mitov.com/OpenWireIDENewRunning.png
http://www.mitov.com/OpenWireIDENew1.png

Plan to release it in Beta in the next 2-3 weeks.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 7 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 1:39 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods home: >wine OpenWireIDE.exe

Reply by email

Martin
to Sven Barth: var, const, type....) and I realized, that thi's a 2 entirely different things. keyword.…
Sven Barth wrote 16 lines
> The above is NOT an anonymous function. It is a reference to a term. > I am not voting for it, but IF it was done, then it should have its own keyword. > > It would not allow for var, type or anything (and it will only work for functions, not procedures.) > a.sort(LambdaTerm TMyCompare do x > y) > or > a.sort(TermRef TMyCompare(x > y) ) This is basically what my idea behind the lambs syntax was: only one expression or statement and no variable, type or constant declarations. And for more complex use case there are either Delphi's anonymous functions or FPC's nested procedures/functions.

Ok, so then it is important, that they are distinguished. Starting with their own name. We MUST NOT call them anonymous functions. (despite the do construct a function. But they are not, because the skip the Result:= part and other)

Technically they are a subset:
1- like a function, they have a result
2- like a function the have zero, 1 or more params 3- not like a functions, they can not have var or out param

   Well you can construct cases were they are possible:  (* Result := *)

1 + Foo(VarParam);
But I think they should not be allowed
4- There body must always contain a RHS term/expression This also results in that the can only be passed for functions 5- begin end is not allowed (would not be an RHS

About 4) If you want procedures to, then we can not use an RHS, because a procedure needs a full statement in the body.
That would mean functions would have to include the "Result :=". There is no way of smart detection, because a function can also sot the result by doing "CallFoo(Result)" (CallFoo has an out param) It is either or, but no mixture.
Even if it goes for proceddure style, 5 should still be considered.

Show quoted text 12 lines
> anonymous function, then would *always* require > a. sort( Function; prototype TMyCompare; [var ...] begin ... end ) > > the protopybe (modifier) could work for named procedures too. (THey would be required NOT to have any params) > Function Foo; prototype TMyCompare; > [var ...] > begin ... end Ah! Now with the named example I understand the use of the ";" after the "function"...

I think using a modifier is the best way to specify the parameter template.

Reply by email

Paul Ishenin
to Marco van de Voort: In our previous episode, Graeme Geldenhuys said: Of course it was. Objects are not a…
Marco van de Voort wrote 6 lines
I chose the latter. Compatibility. All the way. No compromise. Is it pure? No. Is it perfect? No. Is it better than the alternative? Yes. Currently FPC is much dirtier than Delphi if only because it has two implementations for everything.

I'm totally agree. 2 implementations complicates the compiler and complicates the use of the compiler. Component developers and those who plant to port their delphi projects will not use objfpc mode if it will not be delphi compatible.

Best regards,
Paul Ishenin

Reply by email

Sven Barth
to Paul Ishenin
"Paul Ishenin" wrote 6 lines
04.03.2013 18:29, Marco van de Voort wrote: > I chose the latter. Compatibility. All the way. No compromise. > > Is it pure? No. Is it perfect? No. Is it better than the alternative?

Yes.

Show quoted text 6 lines
> > Currently FPC is much dirtier than Delphi if only because it has two > implementations for everything. I'm totally agree. 2 implementations complicates the compiler and

complicates the use of the compiler. Component developers and those who plant to port their delphi projects will not use objfpc mode if it will not be delphi compatible.

ObjFPC mode is not compatible with mode Delphi, because of conscious decisions. Think for example about the "@" for procedure variable assignments here or the use of symbolic operator names for overload declarations, instead of words like Delphi did it. And generics are a further example.

Regards,
Sven

Reply by email

Paul Ishenin
to Sven Barth
Sven Barth wrote 5 lines
ObjFPC mode is not compatible with mode Delphi, because of conscious decisions. Think for example about the "@" for procedure variable assignments here or the use of symbolic operator names for overload declarations, instead of words like Delphi did it. And generics are a further example.

And I would left (if needed) only those minimal differences. Or even tried to reduce (removed own generics implementation and left only Delphi compatible). In any case I would not add more incompatibilities.

Many times the main point to have incompatibilites was: "We implemented it earlier". But regards generics how we implemeneted it earlier? Even now they have some bugs/missing features. And in 2009 when Delphi announced them they had much more (you know of course). That was more a prototype of generics. But inspite of that we did not drop our own implementation.

Regards for-in loop. To add it to objfpc mode I had to add 'enumerator' keyword. Who uses it? 1.5 developers who wants to see pascal clean?

Besides that I'm not against own features like string case or '+=' operations but I strongly against 2 implementations of 1 feature: one to be delphi compatible, one to satisfy few people from pascal community.

Best regards,
Paul Ishenin

Reply by email

Michael Van Canneyt
to Sven Barth: Yes. complicates the use of the compiler. Component developers and those who plant to…
Sven Barth wrote 15 lines
Am 05.03.2013 04:55 schrieb "Paul Ishenin" : > > 04.03.2013 18:29, Marco van de Voort wrote: > >> I chose the latter. Compatibility. All the way. No compromise. >> >> Is it pure? No. Is it perfect? No. Is it better than the alternative? Yes. >> >> Currently FPC is much dirtier than Delphi if only because it has two >> implementations for everything. > > > I'm totally agree. 2 implementations complicates the compiler and complicates the use of the compiler. Component developers and those who plant to port their delphi projects will not use objfpc mode if it will not be delphi compatible.

Of course not.

The whole idea of objfpc mode is that it is *not* Delphi compatible. If it had to be Delphi compatible, we would not have had to introduce it.

It aims to give the same functionality Delphi offers, but implemented in what FPC developers consider a proper 'Object Pascal' way.

ObjFPC mode is not compatible with mode Delphi, because of conscious decisions. Think for example about the "@" for procedure variable assignments here or the use of symbolic operator names for overload declarations, instead of words like Delphi did it. And generics are a further example.

Exactly.

Michael.

Reply by email

Michael Van Canneyt
to Paul Ishenin: And I would left (if needed) only those minimal differences. Or even tried to reduce…
Paul Ishenin wrote 11 lines
05.03.13, 14:10, Sven Barth wrote: > ObjFPC mode is not compatible with mode Delphi, because of conscious > decisions. Think for example about the "@" for procedure variable > assignments here or the use of symbolic operator names for overload > declarations, instead of words like Delphi did it. And generics are a > further example. And I would left (if needed) only those minimal differences. Or even tried to reduce (removed own generics implementation and left only Delphi compatible). In any case I would not add more incompatibilities.

With such an attitude you should remove objfpc (and perhaps all non-delphi modes) alltogether, and rename Free Pascal to Free Delphi.

Michael.

Reply by email

Paul Ishenin
to Michael Van Canneyt
Michael Van Canneyt wrote
With such an attitude you should remove objfpc (and perhaps all non-delphi modes) alltogether, and rename Free Pascal to Free Delphi.

The situation with FPC and Delphi is very like to what had happened with browsers. Every had it own vision of CSS, JS and HTML. Currently then finally understood that these dirrences are bad.

So if I could I would organaize some forum between Delphi and FPC developers where all new features before been implemented had been discussed first and if accepted nobody could implement it different. I tried to contact with some delphi team members on their forum on twitter and on some blogs but without result.

Regards FPC, I would indeed remove FPC mode. Those who need it can use FPC 2.6. I would also minimize the difference between objfpc and delphi modes.

Best regards,
Paul Ishenin

Reply by email

Sven Barth
to Paul Ishenin: And I would left (if needed) only those minimal differences. Or even tried to reduce…
Paul Ishenin wrote 18 lines
05.03.13, 14:10, Sven Barth wrote: > ObjFPC mode is not compatible with mode Delphi, because of conscious > decisions. Think for example about the "@" for procedure variable > assignments here or the use of symbolic operator names for overload > declarations, instead of words like Delphi did it. And generics are a > further example. And I would left (if needed) only those minimal differences. Or even tried to reduce (removed own generics implementation and left only Delphi compatible). In any case I would not add more incompatibilities. Many times the main point to have incompatibilites was: "We implemented it earlier". But regards generics how we implemeneted it earlier? Even now they have some bugs/missing features. And in 2009 when Delphi announced them they had much more (you know of course). That was more a prototype of generics. But inspite of that we did not drop our own implementation.

Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert every commit that tries to do so, because not only do we have to keep backwards compatibility, but the Delphi syntax is a nightmare to parse.

Mode ObjFPC is not for Delphi compatiblity. It's there to implement a cleaner variant of the (Object) Pascal language (and Michael wrote), and if that means higher maintenance burden, so be it. Somewhen in the future we should do a rewrite of the parser anyway and then we can learn from the problems we faced currently and implement it in a way that we can easily extend the language with different implementations (just like was done for the backend).

Regards,
Sven

Reply by email

Michael Van Canneyt
to Paul Ishenin: The situation with FPC and Delphi is very like to what had happened with browsers. Every…
Paul Ishenin wrote 7 lines
05.03.13, 15:57, Michael Van Canneyt wrote: > With such an attitude you should remove objfpc (and perhaps all > non-delphi modes) alltogether, and rename Free Pascal to Free Delphi. The situation with FPC and Delphi is very like to what had happened with browsers. Every had it own vision of CSS, JS and HTML. Currently then finally understood that these dirrences are bad.

You piched a wrong comparison. They are still different in all browsers. Each browser has its own extensions of these "standards" as any web developer will tell you. There is some common ground (and even this is sometimes interpreted differently), but that is it.

Show quoted text 5 lines
So if I could I would organaize some forum between Delphi and FPC developers where all new features before been implemented had been discussed first and if accepted nobody could implement it different. I tried to contact with some delphi team members on their forum on twitter and on some blogs but without result.

I do not believe they will ever do this. Why would they want to ? They (think that they) rule the Pascal community.
They do not care a fig for Lazarus/FPC.

And that is why we have objfpc mode.

Delphi mode is 'Object pascal according to Embarcadero'

ObjFPC mode is 'Object Pascal according to Free Pascal'

There is nothing wrong with having ObjFPC mode, and the bigger the differences are, the better.

The only thing it costs you is some extra cases in parsing, so no maintenance whatsoever. The rest of the compiler remains the same, as the functionality is equal.

Michael.

Reply by email

Michael Van Canneyt
to Sven Barth: Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert…
Sven Barth wrote 28 lines
Am 05.03.2013 07:56, schrieb Paul Ishenin: > 05.03.13, 14:10, Sven Barth wrote: > >> ObjFPC mode is not compatible with mode Delphi, because of conscious >> decisions. Think for example about the "@" for procedure variable >> assignments here or the use of symbolic operator names for overload >> declarations, instead of words like Delphi did it. And generics are a >> further example. > > And I would left (if needed) only those minimal differences. Or even tried > to reduce (removed own generics implementation and left only Delphi > compatible). In any case I would not add more incompatibilities. > > Many times the main point to have incompatibilites was: "We implemented it > earlier". But regards generics how we implemeneted it earlier? Even now > they have some bugs/missing features. And in 2009 when Delphi announced > them they had much more (you know of course). That was more a prototype of > generics. But inspite of that we did not drop our own implementation. Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert every commit that tries to do so, because not only do we have to keep backwards compatibility, but the Delphi syntax is a nightmare to parse. Mode ObjFPC is not for Delphi compatiblity. It's there to implement a cleaner variant of the (Object) Pascal language (and Michael wrote), and if that means higher maintenance burden, so be it. Somewhen in the future we should do a rewrite of the parser anyway and then we can learn from the problems we faced currently and implement it in a way that we can easily extend the language with different implementations (just like was done for the backend).

+1

Michael.

Reply by email

Paul Ishenin
to Sven Barth: Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert…
Sven Barth wrote
Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert every commit that tries to do so, because

Sven, relax - FPC is not your own project and not mine. We can't simple commit or revert what we want.

not only do we have to keep backwards compatibility, but the Delphi syntax is a nightmare to parse.

Yes, it is hard to parse but anyway you need to implement it. So this argument if false. And regards backward compatibility - it is not too much places to fix: some in FPC itself and some in Lazarus components.

Mode ObjFPC is not for Delphi compatiblity. It's there to implement a cleaner variant of the (Object) Pascal language (and Michael wrote), and if that means higher maintenance burden, so be it.

That cleaner variants split pascal for nothing - to make 3-5 developers happy.

Best regards,
Paul Ishenin

Reply by email

Michael Van Canneyt
to Paul Ishenin
Paul Ishenin wrote 7 lines
05.03.13, 16:30, Sven Barth wrote: > Just to say one thing clear: I will NOT drop FPC's generic > implementation and I'll revert every commit that tries to do so, because Sven, relax - FPC is not your own project and not mine. We can't simple commit or revert what we want.

Of course we can, if you violate a basic rule: do not undo other peoples work.

Show quoted text 13 lines
> not only do we have to keep backwards compatibility, but the Delphi > syntax is a nightmare to parse. Yes, it is hard to parse but anyway you need to implement it. So this argument if false. And regards backward compatibility - it is not too much places to fix: some in FPC itself and some in Lazarus components. > Mode ObjFPC is not for Delphi compatiblity. It's there to implement a > cleaner variant of the (Object) Pascal language (and Michael wrote), and > if that means higher maintenance burden, so be it. That cleaner variants split pascal for nothing - to make 3-5 developers happy.

It does not split. It offers people the choice.

This is the basis of open source: Having a choice.

You may think that Delphi is the best thing since sliced bread, but not everyone thinks so.

There are several people on the list that do not like what Delphi is doing to the pascal language. The way Embarcadero treats the Pascal Language I am more and more going to this camp. More so with every release of Delphi.

You must live with this fact, as I must live with your love of Delphi.

We do not deny you your work on Delphi mode.

We expect you not to deny us our work on objfpc mode.

Michael.

Reply by email

Sven Barth
to Paul Ishenin: Sven, relax - FPC is not your own project and not mine. We can't simple commit or revert…
Paul Ishenin wrote 5 lines
> Just to say one thing clear: I will NOT drop FPC's generic > implementation and I'll revert every commit that tries to do so, because Sven, relax - FPC is not your own project and not mine. We can't simple commit or revert what we want.

I'm sorry that it sounded a bit harsh, but I consider the topics backwards compatibility and clean language design very serious. And parsing Delphi's syntax is everything, but not clean...

Show quoted text 7 lines
> not only do we have to keep backwards compatibility, but the Delphi > syntax is a nightmare to parse. Yes, it is hard to parse but anyway you need to implement it. So this argument if false. And regards backward compatibility - it is not too much places to fix: some in FPC itself and some in Lazarus components.

Just for your information: I will implement generic methods will full requirement for "generic" and "specialize" in mode ObjFPC (and no, you can't change my opinion on that).

And regarding backwards compatibility: we are not only talking about FPC and Lazarus. There are enough people around that use FPC's generic syntax and that alone is reason enough to keep it.

Show quoted text 7 lines
> Mode ObjFPC is not for Delphi compatiblity. It's there to implement a > cleaner variant of the (Object) Pascal language (and Michael wrote), and > if that means higher maintenance burden, so be it. That cleaner variants split pascal for nothing - to make 3-5 developers happy.

There seem to be enough persons that use mode ObjFPC and its generics and seem to be happy about it. Especially those that don't care about Delphi compatibility. Also it seems that those that like to develop in Delphi are the only ones complaining... or do you hear from any MacPas developer that mode ObjFPC does not support "return", "c" or "$ifc"?

Regards,
Sven

Reply by email

Graeme Geldenhuys
to Howard Page-Clark: You can simulate this in FPC as well as TP by using a local typed constant. e.g. function…
Howard Page-Clark wrote 10 lines
You can simulate this in FPC as well as TP by using a local typed constant. e.g. function GetValue: integer; const value: integer = 0; begin Inc(value); Result:= value; end;

I've seen this before, and always been baffled by this. How can you increment a "constant"? If you can, it is then a variable, no?

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys
Graeme Geldenhuys wrote 15 lines
On 2013-03-04 20:33, Howard Page-Clark wrote: > > You can simulate this in FPC as well as TP by using a local typed > constant. e.g. > > function GetValue: integer; > const value: integer = 0; > begin > Inc(value); > Result:= value; > end; I've seen this before, and always been baffled by this. How can you increment a "constant"? If you can, it is then a variable, no?

A leftover from the TP days.
A typed constant acts as an initialized variable.

You can disable this construct with:
http://www.freepascal.org/docs-html/prog/progsu42.html

Michael.

Reply by email

Sven Barth
to Graeme Geldenhuys: I've seen this before, and always been baffled by this. How can you increment a…
Graeme Geldenhuys wrote 13 lines
On 2013-03-04 20:33, Howard Page-Clark wrote: > You can simulate this in FPC as well as TP by using a local typed > constant. e.g. > > function GetValue: integer; > const value: integer = 0; > begin > Inc(value); > Result:= value; > end; I've seen this before, and always been baffled by this. How can you increment a "constant"? If you can, it is then a variable, no?

In Turbo Pascal these typed constants were used as the poor man's visibility managment. You basically had a global variable that only that function (and nested ones) can access.

In Delphi the $J switch was introduced which is disabled by default, which means that typed constants are not writeable. You can nevertheless switch it on.

Note: The important point here is that it is a typed constant. And there typed constants and variables are technically the same (both are located in the initalized read/write area of the executable file), while true constants are either inserted directly into the code (ordinals, floating point values) or are located in a read only area of the executable (strings) [if the format does not support a readonly area they are located in the read/write one as well though].

Regards,
Sven

Reply by email

Paul Ishenin
to Sven Barth: I'm sorry that it sounded a bit harsh, but I consider the topics backwards compatibility…
Sven Barth wrote
Just for your information: I will implement generic methods will full requirement for "generic" and "specialize" in mode ObjFPC (and no, you can't change my opinion on that).

Yes, I didn't expect my mails will suddenly change your opinion. And even if they would change there are enough fpc team members who will protected objfpc generics :) I only hope to stop duplicate implementation of other delphi features.

And regarding backwards compatibility: we are not only talking about FPC and Lazarus. There are enough people around that use FPC's generic syntax and that alone is reason enough to keep it.

Enough - how much? 50 or 100 projects? What will be needed to make them work with dephi syntax? Remove word generic and specialize?

Especially those that don't care about Delphi compatibility. Also it seems that those that like to develop in Delphi are the only ones complaining...

Think about component and applications developers who need to care about FPC and Delphi. Less incompatibilities FPC will have more 3rd party components and applications it will get.

I remember author of Total Commander who had failed to port his project to FPC + Laz because of many incompatilities in both projects.

I remember Fib+ developer who stoped his effort to port component to FPC after some found incompatibilities.

There is nothing good in incompatibilities.

Best regards,
Paul Ishenin

Reply by email

Sven Barth
to Paul Ishenin
Paul Ishenin wrote 10 lines
05.03.13, 17:14, Sven Barth wrote: > Just for your information: I will implement generic methods will full > requirement for "generic" and "specialize" in mode ObjFPC (and no, you > can't change my opinion on that). Yes, I didn't expect my mails will suddenly change your opinion. And even if they would change there are enough fpc team members who will protected objfpc generics :) I only hope to stop duplicate implementation of other delphi features.

I won't remove your hope, but I'll also not do anything to fulfill it :P

Show quoted text 6 lines
> And regarding backwards compatibility: we are not only talking about FPC > and Lazarus. There are enough people around that use FPC's generic > syntax and that alone is reason enough to keep it. Enough - how much? 50 or 100 projects? What will be needed to make them work with dephi syntax? Remove word generic and specialize?

Once we support generic functions/procedures (which Delphi does not support) it will be more :)

Show quoted text 7 lines
> Especially those that don't care about > Delphi compatibility. Also it seems that those that like to develop in > Delphi are the only ones complaining... Think about component and applications developers who need to care about FPC and Delphi. Less incompatibilities FPC will have more 3rd party components and applications it will get.

For exactly this purpose we have the mode Delphi. And if something is not working there it's either a missing feature, a bug or something that we just plain refuse to support... (e.g. in Delphi you can have one set element multiple times in the same set constructor: [objectdef, objectdef, objectdef])

I remember author of Total Commander who had failed to port his project to FPC + Laz because of many incompatilities in both projects.

And some differences are by design. Think about resource string handling here. We might provide the LoadResString function/callback, but it's just a dummy, because FPC's resource strings work differently. The same for Lazarus: some differences are by design, because Lazarus is not fixed to the Windows platform (as a Lazarus developer you should know this).

I remember Fib+ developer who stoped his effort to port component to FPC after some found incompatibilities. There is nothing good in incompatibilities.

As already wrote by Michael and me: it's not the purpose of mode ObjFPC to provide compatibility.

Regards,
Sven

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt: Of course we can, if you violate a basic rule: do not undo other peoples work. It does…
Michael Van Canneyt wrote 5 lines
You may think that Delphi is the best thing since sliced bread, but not everyone thinks so. There are several people on the list that do not like what Delphi is doing to the pascal language.

+1000

I think Embarcadero is butchering the Object Pascal language. Stealing ideas (and worse, the syntax) from other languages verbatim. They don't put any thought in there language design like Borland did.

For that reason, I love FPC and the objfpc mode. ALL my products are developer only in objfpc mode. The syntax is much cleaner and true to Pascal.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Paul Ishenin
to Michael Van Canneyt: Of course we can, if you violate a basic rule: do not undo other peoples work. It does…
Michael Van Canneyt wrote
Of course we can, if you violate a basic rule: do not undo other peoples work.

Can you imagine me or anybody other in FPC team who do so without total agreement?

It does not split. It offers people the choice.

Again we see one thing from different sides. For me this is not a benefit but defect requires elimination.

This is the basis of open source: Having a choice.

Yes, but I'd love to see this choise not inside 1 project.

We do not deny you your work on Delphi mode. We expect you not to deny us our work on objfpc mode.

Okay.

Best regards,
Paul Ishenin

Reply by email

Michael Van Canneyt
to Paul Ishenin: Yes, I didn't expect my mails will suddenly change your opinion. And even if they would…
Paul Ishenin wrote
Think about component and applications developers who need to care about FPC and Delphi. Less incompatibilities FPC will have more 3rd party components and applications it will get.

For this, mode delphi exists.

Show quoted text 7 lines
I remember author of Total Commander who had failed to port his project to FPC + Laz because of many incompatilities in both projects. I remember Fib+ developer who stoped his effort to port component to FPC after some found incompatibilities. There is nothing good in incompatibilities.

There is no incompatibility. There is choice.

People who wish to port Delphi code should use {$mode delphi}. And from what I see, people that come from Delphi automatically use $mode delphi. Good, that is what it is for.

I fully agree with you that Delphi mode should try and be as Delphi compatible as possible.

All that is being argued is that there must be the choice to have another mode where people that do not care or agree with Delphi, can implement things the way they think it should be done.

FPC is as old as Delphi.
I think that gives us the right of speech and the right to voice our own opinion.

Michael.

Reply by email

Sven Barth
to Graeme Geldenhuys: +1000 I think Embarcadero is butchering the Object Pascal language. Stealing ideas (and…
Graeme Geldenhuys wrote 15 lines
On 2013-03-05 09:12, Michael Van Canneyt wrote: > You may think that Delphi is the best thing since sliced bread, > but not everyone thinks so. > > There are several people on the list that do not like what Delphi is doing to > the pascal language. +1000 I think Embarcadero is butchering the Object Pascal language. Stealing ideas (and worse, the syntax) from other languages verbatim. They don't put any thought in there language design like Borland did. For that reason, I love FPC and the objfpc mode. ALL my products are developer only in objfpc mode. The syntax is much cleaner and true to Pascal.

@Paul: see? :)

Regards,
Sven

Reply by email

Michael Van Canneyt
to Paul Ishenin: Can you imagine me or anybody other in FPC team who do so without total agreement? Again…
Paul Ishenin wrote 7 lines
05.03.13, 17:12, Michael Van Canneyt wrote: > Of course we can, if you violate a basic rule: do not undo other peoples > work. Can you imagine me or anybody other in FPC team who do so without total agreement?

I hope not :)

> It does not split. It offers people the choice. Again we see one thing from different sides. For me this is not a benefit but defect requires elimination.

This is your right.

> This is the basis of open source: Having a choice. Yes, but I'd love to see this choise not inside 1 project.

Since it is not your project to begin with, you'll have to learn to live with this choice.

Like I have to live with your implementations.

Live and let live.

Michael.

Reply by email

Henry Vermaak
to Michael Van Canneyt: Of course we can, if you violate a basic rule: do not undo other peoples work. It does…
Michael Van Canneyt wrote
You may think that Delphi is the best thing since sliced bread, but not everyone thinks so.

And with the attitude of, e.g. Boian, we see that it's simply too hard to please hard-core delphi fanboys. They're all "take" and no "give". I look forward to the day when the fpc developers will realise that playing eternal catch-up is never going to work.

There are several people on the list that do not like what Delphi is doing to the pascal language. The way Embarcadero treats the Pascal Language I am more and more going to this camp. More so with every release of Delphi.

Much kudos to Sven for really trying to keep the language sane.

Henry

Reply by email

Sven Barth
to Henry Vermaak: And with the attitude of, e.g. Boian, we see that it's simply too hard to please…
Henry Vermaak wrote 7 lines
On Tue, Mar 05, 2013 at 10:12:04AM +0100, Michael Van Canneyt wrote: > You may think that Delphi is the best thing since sliced bread, > but not everyone thinks so. And with the attitude of, e.g. Boian, we see that it's simply too hard to please hard-core delphi fanboys. They're all "take" and no "give". I look forward to the day when the fpc developers will realise that playing eternal catch-up is never going to work.

Somehow I hope we reach this day sooner than later...

Show quoted text 5 lines
> There are several people on the list that do not like what Delphi is doing to > the pascal language. The way Embarcadero treats the Pascal Language > I am more and more going to this camp. More so with every release of > Delphi. Much kudos to Sven for really trying to keep the language sane.

Thanks, I try my best :)

Regards,
Sven

Reply by email

Marco van de Voort
to Sven Barth: Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert…

In our previous episode, Sven Barth said:

Show quoted text 7 lines
> when Delphi announced them they had much more (you know of course). > That was more a prototype of generics. But inspite of that we did not > drop our own implementation. Just to say one thing clear: I will NOT drop FPC's generic implementation and I'll revert every commit that tries to do so, because not only do we have to keep backwards compatibility, but the Delphi syntax is a nightmare to parse.

But you need to anyway because of mode delphi, so what is the point?

Reply by email

Alexander Klenin
to Paul Ishenin: I see you, Graeme, Michael and probably some more 5-6 developers. Paul Ishenin
Paul Ishenin wrote
05.03.13, 17:55, Sven Barth wrote: I see you, Graeme, Michael and probably some more 5-6 developers.

The level of Delphi compatibility vs. syntax quality is, as always in engineering,
a matter of compromise and cost/benefit analysis.
For example, and trying to return to the topic of this thread, I think "embedded" anonymous functions should be implemented for both Delphi and ObjFPC mode --
even if there will be better alternatives in ObjFPC. This way, at least in one direction compatibility will be preserved, while people preferring "pure Pascal" style will still be able to ignore Delphi syntax in their FPC-only projects.
On the other hand, default closure behavior should perhaps be implemented differently.
There are three choices for anonymous function without additional annotations:
1) No closure
2) By-reference closure
3) By-value closure

Delphi currently implements (2) which is inconsistent with nested functions and introduces a subtle
and unexpected performance drop. I suggest (1) in ObjFPC mode, but (2) in Delphi mode,
with additional modeswitch, as usual.

This is why I propose the following plan:

1) Implement Delphi-like anonymous functions syntax, without closures
2) Implement Delphi-like by-reference closures
3) Implement ObjFPC-specific named closures with explicit by-value/by reference options
4) Implement ObjFPC-specific shortened syntax

Discussion of ObjFPC extension may continue while the implementation of (1) and (2) is in progress.

Alexander S. Klenin

Reply by email

Alexander Klenin
to Marco van de Voort: In our previous episode, Sven Barth said: But you need to anyway because of mode delphi,…
Marco van de Voort wrote 6 lines
> Just to say one thing clear: I will NOT drop FPC's generic > implementation and I'll revert every commit that tries to do so, because > not only do we have to keep backwards compatibility, but the Delphi > syntax is a nightmare to parse. But you need to anyway because of mode delphi, so what is the point?

It is hard to parse for humans as well as for the compiler.

Alexander S. Klenin

Reply by email

Marco van de Voort
to Alexander Klenin

In our previous episode, Alexander Klenin said:

Show quoted text 6 lines
>> not only do we have to keep backwards compatibility, but the Delphi >> syntax is a nightmare to parse. > > But you need to anyway because of mode delphi, so what is the point? It is hard to parse for humans as well as for the compiler.

That's a matter of taste. I'm not sb who in general favours terse notation, but I don't really see the benefit of the FPC syntax for humans.

Reply by email

Michael Fuchs
to Michael Van Canneyt: A leftover from the TP days. A typed constant acts as an initialized variable. You can…
Michael Van Canneyt wrote 8 lines
> I've seen this before, and always been baffled by this. How can you > increment a "constant"? If you can, it is then a variable, no? A leftover from the TP days. A typed constant acts as an initialized variable. You can disable this construct with: http://www.freepascal.org/docs-html/prog/progsu42.html

This should be the default in ObjFpc mode.

Michael

Reply by email

ListMember
to Sven Barth: Somehow I hope we reach this day sooner than later... Thanks, I try my best :) Sven
Sven Barth wrote
Thanks, I try my best :)

I know you do.

And, since generics has also been mentioned in this thread, here is something I'd like to table/mention (or, rather, use you as a sounding board, if I may).

Sometimes writing generic routines that are truly generic is hard since the types it needs to handle can be tough to genericise (strings, ordinals, objects etc. are not always treatable in generic routines in the same way).

The solution to this might be to write different generic routines for each offending type but this means duplication plenty of code in the process which in turn defeates quite a bit of the purpose of having generics.

This brings me to wonder if it would be possible to pass some constant (or set of constants, or something similar) to generic routine such that this/these option(s) would be treated as compiles options within the implementation of the generic routine.

Reply by email

Sven Barth
to Michael Fuchs: This should be the default in ObjFpc mode. Michael
Michael Fuchs wrote 12 lines
Am 05.03.2013 10:25, schrieb Michael Van Canneyt: >> I've seen this before, and always been baffled by this. How can you >> increment a "constant"? If you can, it is then a variable, no? > > A leftover from the TP days. A typed constant acts as an initialized > variable. > > You can disable this construct with: > http://www.freepascal.org/docs-html/prog/progsu42.html This should be the default in ObjFpc mode.

Two words: backwards compatibility.

Regards,
Sven

Reply by email

Sven Barth
to Alexander Klenin: The level of Delphi compatibility vs. syntax quality is, as always in a matter of…
Alexander Klenin wrote 11 lines
This is why I propose the following plan: 1) Implement Delphi-like anonymous functions syntax, without closures 2) Implement Delphi-like by-reference closures 3) Implement ObjFPC-specific named closures with explicit by-value/by reference options 4) Implement ObjFPC-specific shortened syntax Discussion of ObjFPC extension may continue while the implementation of (1) and (2) is in progress.

I basically agree. Though for now anonymous functions should be either bound to mode Delphi or at least a modeswitch (enabled by default in mode Delphi and disabled everywhere else). [or maybe we should add such newer extensions to mode DelphiUnicode?] The type "reference to ..." should be available in either mode though (independantly of anonymous functions).

Regards,
Sven

Reply by email

Sven Barth
to Marco van de Voort: In our previous episode, Sven Barth said: But you need to anyway because of mode delphi,…
Marco van de Voort wrote 9 lines
In our previous episode, Sven Barth said: >> when Delphi announced them they had much more (you know of course). >> That was more a prototype of generics. But inspite of that we did not >> drop our own implementation. > Just to say one thing clear: I will NOT drop FPC's generic > implementation and I'll revert every commit that tries to do so, because > not only do we have to keep backwards compatibility, but the Delphi > syntax is a nightmare to parse. But you need to anyway because of mode delphi, so what is the point?

Because in mode Delphi the following will not work for quite some time (because it is so damn hard to parse):

=== example begin ===

SomeVar := SomeFunc<Something> - SomeType<Something>.SomeMethod *
SomeOtherType<Something>.SomeMethod<Something>;

=== example end ===

while this will be much easier to implement:

=== example begin ===

SomeVar := specialize SomeFunc<Something> - specialize
SomeType<Something>.SomeMethod * specialize
SomeOtherType<Something>.specialize SomeMethod<Something>;

=== example end ===

(though "specialize SomeType<Something>" and "specialize SomeOtherType<Something>" are more likely to stay in type sections for now...)

Regards,
Sven

Reply by email

Alexander Klenin
to Sven Barth
Sven Barth wrote 20 lines
SomeVar := SomeFunc<Something> - SomeType<Something>.SomeMethod * SomeOtherType<Something>.SomeMethod<Something>; === example end === while this will be much easier to implement: === example begin === SomeVar := specialize SomeFunc<Something> - specialize SomeType<Something>.SomeMethod * specialize SomeOtherType<Something>.specialize SomeMethod<Something>; === example end === (though "specialize SomeType<Something>" and "specialize SomeOtherType<Something>" are more likely to stay in type sections for now...)

BTW, does anybody know why on earth the "sane" objFPC syntax still have those angle brackets instead of normal round ones?

Alexander S. Klenin

Reply by email

Sven Barth
to Alexander Klenin
Alexander Klenin wrote 23 lines
On Wed, Mar 6, 2013 at 12:16 AM, Sven Barth wrote: > SomeVar := SomeFunc<Something> - SomeType<Something>.SomeMethod * > SomeOtherType<Something>.SomeMethod<Something>; > > === example end === > > while this will be much easier to implement: > > === example begin === > > SomeVar := specialize SomeFunc<Something> - specialize > SomeType<Something>.SomeMethod * specialize > SomeOtherType<Something>.specialize SomeMethod<Something>; > > === example end === > > (though "specialize SomeType<Something>" and "specialize > SomeOtherType<Something>" are more likely to stay in type sections for > now...) > BTW, does anybody know why on earth the "sane" objFPC syntax still have those angle brackets instead of normal round ones?

I don't know why the one who first implemented them chose them, but now the reason is backwards compatibility.

Please note that I wouldn't have choosen round brackets either (potential conflicts with type casting) but more something like this:

=== snippet begin ===

specialize SomeType with (Something)

=== snippet end ===

Regards,
Sven

Reply by email

Mattias Gaertner
to Sven Barth

Sven Barth hat am 5. März 2013 um 14:27
geschrieben:

[...] Please note that I wouldn't have choosen round brackets either (potential conflicts with type casting)

?
Can you give an example?

Mattias

Reply by email

Alexander Klenin
to Sven Barth: I don't know why the one who first implemented them chose them, but now the reason is…
Sven Barth wrote 5 lines
I don't know why the one who first implemented them chose them, but now the reason is backwards compatibility. Please note that I wouldn't have choosen round brackets either (potential conflicts with type casting)

Is not "specialize" keyword there to prevent exactly this?

specialize SomeType with (Something)

I would like to propose a modification to one of the principles we brought up in this thread: "prefer keywords to punctuation ... but not to the point of becoming COBOL" :)

Alexander S. Klenin

Reply by email

Sven Barth
to Alexander Klenin
Alexander Klenin wrote 7 lines
On Wed, Mar 6, 2013 at 12:27 AM, Sven Barth wrote: > I don't know why the one who first implemented them chose them, but now the > reason is backwards compatibility. > > Please note that I wouldn't have choosen round brackets either (potential > conflicts with type casting) Is not "specialize" keyword there to prevent exactly this?

Right... I forgot :)

Regards,
Sven

Reply by email

Sven Barth
to Mattias Gaertner: Sven Barth hat am 5. März 2013 um 14:27 geschrieben: ? Can you give an example? Mattias
Mattias Gaertner wrote 7 lines
Sven Barth hat am 5. März 2013 um 14:27 geschrieben: > [...] > Please note that I wouldn't have choosen round brackets either > (potential conflicts with type casting) ? Can you give an example?

Forget what I wrote... As I've written in my mail to Alexander, I've forgotten that we have the "specialize" as an introductory keyword.

Regards,
Sven

Reply by email

Vasiliy Kevroletin
to waldo kitty: i'm trying to understand what you mean by i've done something that i think is what you…
waldo kitty wrote 34 lines
> It is as I thought about closures before. But this is useless without > capturing > of variables by value. During creation of anonymous method you *can > not bind any > values* to it. Anonymous method have only references to captured > variables. > Pascal don't allows to create static variables inside function like > in c-like > languages. So you also not able to create unique static variable > which available > only to one instance of same anonymous method. Even if implementation > will > create many separate objects for one anonymous function then all > instances will > be equivalent. Because all instances will refer to same data. i'm trying to understand what you mean by > Pascal don't allows to create static variables inside function like in c-like > languages. i've done something that i think is what you speak of but it was in Borland's Turbo Pascal... at least TP6... i don't remember how we did it though and can't find any sample code in my library :( what happened is that the value did not get cleared between invocations of the routine and subsequent executions could use the value already stored... this breaks, of course, if the memory area for the routine is cleared first... _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Word "static" is mistake here, sorry. It should be "local" variable instead. As it was said in this thread: closure is a way to create object (no mean named closure or anonymous). Closure is a routine with all variables which it accesses (or "captures" in terminology of Delphi or C++). So closure is routine + captured data. I expected that Delphi will create one object for one closure.
In example below I was expecting to see creation of 10 different objects. But Delphi creates only 1 object. I was surprised.

=== example
for i := 1 to 10 begin

     arr[i] := procedure begin
                      ...
                  end;

===
All arr[i] have same value(same reference).

Actually Delphi creates object(called FrameObject in Delphi's docs) for closure otherwise it will not work. But Delphi creates this object not for every closure but only for procedure where closure defined. This details described in pdf file which I attached in first message of thread. Also Sven created good comments which describes how Delphi implements closures and how capturing by value should work http://lists.freepascal.org/lists/fpc-devel/2013-March/031588.html.

My confused comment can be reformulated: Delphi doesn't create object for each closure because there is no need to do it. But why many other languages should create object for each closure but Delphi need not ? Because Pascal allows to declare local variables only in beginning of routine. But many c-like languages allows to declare local variables in middle of routine. I will describe on example.

Imagine that you want to create many similar objects in loop like this:

=== example

type TWriter = class
        data: Integer;
        constructor Create(i: Integer);
        procedure Execute;
      end;
constructor TWriter.Create(i: Integer); begin data := i; end;
procedure TWriter.Execute; begin Writeln(data); end;
var i: Integer;
     arr: array[1..10] of TWriter;
begin
   for i := 1 to 10 do
     arr[i] := TWriter.Create(i);
   for i := 1 to 10 do
     arr[i].Execute;
end.
===

=== output
1 2 3 4 5 6 7 8 9 10
===

If someone will try to make same trick using Delphi's anonymous methods(Delphi's implementation of closures) he may try to do this

=== wrong

   for i := 1 to 10 do
     procArr[i] := procedure begin
                     Writeln(i);
                   end;
   for j := 1 to 10 do
     procArr[j]();
===

=== output
11 11 11 11 11 11 11 11 11 11
===

Why? Because all procedures from procArr captured variable 'i' by reference. They access same variable. So this is a problem to simply create "private" data for closure. But you can do it like this:

=== right

function Factory(data: Integer): TProc;
begin
   Result := procedure begin
               Writeln(data);
             end;
end;

...

   for i := 1 to 10 do
     procArr[i] := Factory(i);
   for j := 1 to 10 do
     procArr[j]();

===

=== output
1 2 3 4 5 6 7 8 9 10
===

Just as expected.
Now about local variables and why in other languages simple creation of "private" variable for closure is not a problem.

=== perl
for (my $i = 0; $i < 10; ++$i) {
{

         my $stored = $i;
         $f[$i] = sub { printf $stored }
     }

}

for (my $j = 0; $j < 10; ++$j) {

     $f[$j]();

}
===

=== output
0123456789
===

This is works because:
- each loop iteration creates new variable $stored
- closure captures $stored
- variable $stored is accessible only in it's declaring block { .. } ; at end of loop iteration only closure will save link to it.

So Perl have to create new object for each closure because each closure may contains private data. In Delphi closures also can have private data, but closures created in same function will capture same data. Closures created in same line of code will not only refer to same data but also will have same behaviour. That is why in 1st example of my email Delphi all elements of arr are equal.

Vasiliy K.

Reply by email

Paul Ishenin
to Marcos Douglas: So now we have 7! ;-) I want to keep the language sane too. Marcos Douglas

05.03.13, 21:00, Marcos Douglas пишет:

So now we have 7! ;-) I want to keep the language sane too.

I wrote not about sane/insane. Delphi adds features to pascal the way they want - this is reality. We can't do anything with this. If they add a feature not the sane way we can't undo their feature. From that moment language become so - with this feature. Whether we want or no. Sooner or later we will have to deal with this feature exactly as Delphi developers see it.

What I was against is to add the second implementation for already existent language feature.

But after mail of Michael I already look at this more tolerant now. So please let's stop this endless dispute about nothing. We have different vision and this is good after all.

Best regards,
Paul Ishenin

Reply by email

Florian Klaempfl
to Paul Ishenin: I see you, Graeme, Michael and probably some more 5-6 developers. Paul Ishenin
Paul Ishenin wrote 5 lines
05.03.13, 17:55, Sven Barth wrote: > @Paul: see? :) I see you, Graeme, Michael and probably some more 5-6 developers.

Even if those are the only ones, from the beginning, FPC tried to support all niches. And if someone maintaines a certain niche, the niche will be continued to be support. Actually, I think FPC lives from niches and developers working on niches.

Reply by email

Marcos Douglas
to Paul Ishenin: 05.03.13, 21:00, Marcos Douglas пишет: I wrote not about sane/insane. Delphi adds…
Paul Ishenin wrote 12 lines
05.03.13, 21:00, Marcos Douglas пишет: > So now we have 7! ;-) > I want to keep the language sane too. I wrote not about sane/insane. Delphi adds features to pascal the way they want - this is reality. We can't do anything with this. If they add a feature not the sane way we can't undo their feature. From that moment language become so - with this feature. Whether we want or no. Sooner or later we will have to deal with this feature exactly as Delphi developers see it.

But if something isn't good enough, why spend time to codify this?

What I was against is to add the second implementation for already existent language feature.

Why follow the Delphi even knowing that is the wrong way to implement something?

But after mail of Michael I already look at this more tolerant now. So please let's stop this endless dispute about nothing. We have different vision and this is good after all.

Ok.

Best regards,
Marcos Douglas

Reply by email

Alexander Klenin
to ListMember: I know you do. And, since generics has also been mentioned in this thread, here is…
ListMember wrote
This brings me to wonder if it would be possible to pass some constant (or set of constants, or something similar) to generic routine such that this/these option(s) would be treated as compiles options within the implementation of the generic routine.

Ugh, that is definitely not the right solution.
Some alternatives:
1) Make sure "is" and "as" work with generic types -- maybe they already are?
2) Since currently the specialization has to be named anyway, write non-generic versions for "inconvenient" types, and use inheritance to factor out common code.
3) Implement partial specialization, in C++ style -- fundamental solution, but perhaps an overkill
in the light of the above.

Alexander S. Klenin

Reply by email

waldo kitty
to Howard Page-Clark: You can simulate this in FPC as well as TP by using a local typed constant. e.g. function…
Howard Page-Clark wrote 21 lines
On 04/03/13 6:34, waldo kitty wrote: > i'm trying to understand what you mean by > > > Pascal don't allows to create static variables inside function > > like in c-like languages. > > i've done something that i think is what you speak of but it was in > Borland's Turbo Pascal... at least TP6... i don't remember how we did it > though and can't find any sample code in my library :( You can simulate this in FPC as well as TP by using a local typed constant. e.g. function GetValue: integer; const value: integer = 0; begin Inc(value); Result:= value; end; Successive calls to GetValue() will return 1, 2, 3 etc.

yes, that is exactly what i was thinking of... i just could not find any sample code in my library... as noted, i have used it and it sounds similar to what the OP is looking to do... one thing i used to use it for was counting the number of time that a routine was called during the course of execution... other times i used it were in relation to recursion IIRC...

NOTE: i've never done this with strings but i would guess it would work, too...

Reply by email

waldo kitty
to Graeme Geldenhuys: I've seen this before, and always been baffled by this. How can you increment a…
Graeme Geldenhuys wrote 15 lines
On 2013-03-04 20:33, Howard Page-Clark wrote: > > You can simulate this in FPC as well as TP by using a local typed > constant. e.g. > > function GetValue: integer; > const value: integer = 0; > begin > Inc(value); > Result:= value; > end; I've seen this before, and always been baffled by this. How can you increment a "constant"? If you can, it is then a variable, no?

yep... i also call all named storage items variables even if they are constants... what else do you call them in a generic sense? ;)

Reply by email

Boian Mitov
to Michael Van Canneyt: A pity. Michael.

Agree :-) .
A native Linux version is planned. It will be however done with either Lazarus or Delphi if its Linux version becomes available next year, or our own non Pascal compiler in the next couple of years if that one gets ready.

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 7 lines
-----Original Message----- From: Michael Van Canneyt Sent: Monday, March 04, 2013 11:51 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods A pity.

Reply by email

Boian Mitov
to Henry Vermaak: And with the attitude of, e.g. Boian, we see that it's simply too hard to please…

Hi Henry,

Interesting that you consider me a Delphi fanboy :-D . I don't like it much, but I surely love the anonymous methods :-D . I love the C++11 implementation of anonymous methods more however, but I hate the lack of extensive RTTI in C++ (and FPC).
I am hard to please, and no fan of any specific language. I hate them, and love them equally with only one exception, well maybe 2. I highly dislike Java, and I hate Scheme! :-D .
And BTW: I hate my products too, so that is why I keep working to improve them all the time :-D, they are never good enough for me! I am equal opportunity hater!

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 10 lines
-----Original Message----- From: Henry Vermaak Sent: Tuesday, March 05, 2013 2:05 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods And with the attitude of, e.g. Boian, we see that it's simply too hard to please hard-core delphi fanboys. They're all "take" and no "give". I look forward to the day when the fpc developers will realise that playing eternal catch-up is never going to work.

Reply by email

Boian Mitov
to Alexander Klenin: It is hard to parse for humans as well as for the compiler. Alexander S. Klenin

Hmm... you are running on the assumptions that humans are parsers. I for one do analyze the logic not the sequence, maybe because I usually write code for parallel execution. Humans do not think and follow code as computers, and often code that is easy to parse is difficult to follow by human IMHO. Otherwise we all would have been writing in Assembler ;-) .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 7 lines
-----Original Message----- From: Alexander Klenin Sent: Tuesday, March 05, 2013 3:30 AM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods It is hard to parse for humans as well as for the compiler.

Reply by email

Graeme Geldenhuys
to Marcos Douglas: But if something isn't good enough, why spend time to codify this? Why follow the Delphi…
Marcos Douglas wrote
Why follow the Delphi even knowing that is the wrong way to implement something?

Because like the FPC team have said a million times to me.... because they follow Delphi blindly, and WILL do everything to stay "delphi compatible".

Good thing is, most of these are kept in the 'delphi' compiler mode. The 'objfpc' mode normally get some more pascal love.

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/

Reply by email

Henry Vermaak
to Boian Mitov: Interesting that you consider me a Delphi fanboy :-D . I don't like it much, but I surely…
Boian Mitov wrote 12 lines
Hi Henry, Interesting that you consider me a Delphi fanboy :-D . I don't like it much, but I surely love the anonymous methods :-D . I love the C++11 implementation of anonymous methods more however, but I hate the lack of extensive RTTI in C++ (and FPC). I am hard to please, and no fan of any specific language. I hate them, and love them equally with only one exception, well maybe 2. I highly dislike Java, and I hate Scheme! :-D . And BTW: I hate my products too, so that is why I keep working to improve them all the time :-D, they are never good enough for me! I am equal opportunity hater!

You sure have a lot of smiley faces for a person so full of hate :)

In all seriousness, what were you thinking when you used all the latest features of a language that's closed source? I can understand that it makes your code better (arguably, perhaps), but you've locked yourself into the Delphi world now, and it's unlikely that freepascal will ever satisfy you if you chase after the latest features, since it will take too long to implement and stabilise.

Henry

Reply by email

Boian Mitov
to Henry Vermaak

I equally love and hate the tools (spare Scheme and Java) :-D . So hence the smiling faces.

I needed the performance boos and speed of development they are giving me. The development before that was way too slow :-( . I have increased the productivity multiple times by doing that. I also did more insane things to do that, like writing my own Design time API on top of the Delphi one. This virtually eliminated the need to develop design time editors, as I do it with just adding few attributes now. Second, I am financing the development of our own proprietary development language, and in few years may port everything to it. I also have the option to pay some developers to add the necessary features to FPC if it comes to that :-D .
So I am not short on options :-P .
I am insane, but not "that" insane :-D .

With best regards,
Boian Mitov

------------------------------------------------------- Mitov Software
www.mitov.com
-------------------------------------------------------

Earlier message 15 lines
-----Original Message----- From: Henry Vermaak Sent: Tuesday, March 05, 2013 2:20 PM To: FPC developers' list Subject: Re: [fpc-devel] Delphi anonymous methods You sure have a lot of smiley faces for a person so full of hate :) In all seriousness, what were you thinking when you used all the latest features of a language that's closed source? I can understand that it makes your code better (arguably, perhaps), but you've locked yourself into the Delphi world now, and it's unlikely that freepascal will ever satisfy you if you chase after the latest features, since it will take too long to implement and stabilise.

Reply by email

Frank Church
to Boian Mitov

I have observed a lot of Delphi developers who have written code that needs or depends on the features like anonymous methods, generics, RTTI give up porting to FPC because it proved too difficult, but then it turns out those libraries could greatly enhance FPC usage.

So I think this bullet must be bitten once to enable those libraries to be ported over, by FPC achieving parity or syntax compatibility in that area. Once that is done the FPC development team should make it clear where they don't agree with Embarcadero's approach, so developers who want to port to FPC don't depend on any funny stuff Embarcadero might concoct in the future.

It may even turn out that in the future Delphi will be the one that has to follow FPCs lead or accommodate it, if this issue is successfully resolved, just as Microsoft has had to accommodate Linux.

The more developers can accomplish with FPC and Linux the less relevant the restrictive and proprietary Windows and Mac environments become and that is what FPC devs should keep in sight.

Frank Church ======================= http://devblog.brahmancreations.com

Reply by email

Michael Schnell
to Graeme Geldenhuys: Because like the FPC team have said a million times to me.... because they follow Delphi…
Graeme Geldenhuys wrote
Good thing is, most of these are kept in the 'delphi' compiler mode. The 'objfpc' mode normally get some more pascal love.

+1

AFAIK there is an Apple specific Objective Pascal mode, as well. I think it's really nice to have multiple compilers in one (some tolerable cost regarding compiler speed not withstanding).

-Michael

Reply by email

Sven Barth
to Michael Schnell: +1 AFAIK there is an Apple specific Objective Pascal mode, as well. I think it's really…
Michael Schnell wrote 8 lines
On 03/05/2013 08:52 PM, Graeme Geldenhuys wrote: > Good thing is, most of these are kept in the 'delphi' compiler mode. > The 'objfpc' mode normally get some more pascal love. +1 AFAIK there is an Apple specific Objective Pascal mode, as well. I think it's really nice to have multiple compilers in one (some tolerable cost regarding compiler speed not withstanding).

There is a mode that's compatible to Mac Pascal, but the Objective Pascal is independant of the mode, but is triggered by a modeswitch (as it was specially developed by the FPC and the Mac Pascal communities).

Regards,
Sven

Reply by email

Michael Schnell
to Sven Barth
Sven Barth wrote 5 lines
There is a mode that's compatible to Mac Pascal, but the Objective Pascal is independant of the mode, but is triggered by a modeswitch (as it was specially developed by the FPC and the Mac Pascal communities).

Would it not be nice and more straightforward to have a {$ definition for same, too ?

-Michael

Reply by email

Sven Barth
to Michael Schnell
Michael Schnell wrote 8 lines
On 03/06/2013 01:45 PM, Sven Barth wrote: > There is a mode that's compatible to Mac Pascal, but the Objective > Pascal is independant of the mode, but is triggered by a modeswitch > (as it was specially developed by the FPC and the Mac Pascal > communities). > Would it not be nice and more straightforward to have a {$ definition for same, too ?

What exactly do you mean?

Regards,
Sven

Reply by email

Sven Barth
to Graeme Geldenhuys: To Turbo Pascal yes (ie: tp mode), but surely not ObjFPC? - Graeme - fpGUI Toolkit - a…
Graeme Geldenhuys wrote
On 2013-03-05 13:02, Sven Barth wrote: > Two words: backwards compatibility. To Turbo Pascal yes (ie: tp mode), but surely not ObjFPC?

You must not forget that mode ObjFPC isn't the youngest one either. If we'd freshly design that mode I'd agree with you, but we now have many users that use that mode and might rely on the point that $J+ is set. Only because you don't use it doesn't mean that noone does.

Regards,
Sven

Reply by email

Thaddy
to Michael Schnell: we already have: {$MODE FPC} {$MODE OBTP} {$MODE DELPHI} {$MODE OBJFPC} {$MODE OBJMAC} if…
{$MODE SUBJECTIVE} is more appropriate in this discussion.

But i am by -first - education a political scientist.

Michael Schnell wrote 19 lines
On 03/06/2013 02:37 PM, Sven Barth wrote: > What exactly do you mean? we already have: {$MODE FPC} {$MODE OBTP} {$MODE DELPHI} {$MODE OBJFPC} {$MODE OBJMAC} if {$MODE OBJMAC} not already is for objective Pascal there could be something like {$MODE OBJECTIVE} -Michael _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

ListMember
to Alexander Klenin: Yes, and also generic parameters. procedure TGenegic<T>Proc; begin if T is String then ...
Alexander Klenin wrote 11 lines
On Wed, Mar 6, 2013 at 10:00 PM, Michael Schnell wrote: > On 03/05/2013 05:17 PM, Alexander Klenin wrote: >> 1) Make sure "is" and "as" work with generic types -- maybe they already >> are? > "is" the generic type and/or "is" a certain specialization ? Yes, and also generic parameters. procedure TGenegic<T>Proc; begin if T is String then ... end;

And, from then on, we're going to have to typecast each and every occurence of T..

Even if this was possible for every type of T, I wonder how doing that affects the performance of generics.

That's why I like the idea of passing compiler directives to generics to help eliminate parts of code (from the generic implementation) during compile-time.

Reply by email

Roberto P.
to Thaddy: {$MODE SUBJECTIVE} is more appropriate in this discussion. But i am by -first - education…
{$MODE MINE} would suit as well :-)

2013/3/6 Thaddy

Show quoted text 35 lines
{$MODE SUBJECTIVE} is more appropriate in this discussion. But i am by -first - education a political scientist. On 6-3-2013 15:44, Michael Schnell wrote: > On 03/06/2013 02:37 PM, Sven Barth wrote: > >> What exactly do you mean? >> > > we already have: > {$MODE FPC} > {$MODE OBTP} > {$MODE DELPHI} > {$MODE OBJFPC} > {$MODE OBJMAC} > > if {$MODE OBJMAC} not already is for objective Pascal there could be > something like > > {$MODE OBJECTIVE} > > -Michael > ______________________________**_________________ > fpc-devel maillist - > http://lists.freepascal.org/**mailman/listinfo/fpc-devel<http://lists.freepascal.org/mailman/listinfo/fpc-devel> > ______________________________**_________________ fpc-devel maillist - http://lists.freepascal.org/**mailman/listinfo/fpc-devel<http://lists.freepascal.org/mailman/listinfo/fpc-devel>

Reply by email

Alexander Shishkin
to Sven Barth: I've now read through your PDF and somehow I'd like to have a better implementation in…

03.03.2013 2:22, Sven Barth пишет:

Show quoted text 55 lines
On 02.03.2013 20:55, Sven Barth wrote: >> Also there are open questions which require brainstorm: >> 1. Does Pascal needs other implementation of closures which is different >> from anonymous methods implementation? > > I would say no. After all the method implementation itself stays the > same, but the captured variables should be different. Or what does this > print: I've now read through your PDF and somehow I'd like to have a better implementation in FPC. Let's consider the following code (Note: I've never used anonymous methods yet, so this is what I naively would expect): === code begin === var i: LongInt; SomeProc1, SomeProc2: reference to procedure; begin i := 42; SomeProc1 := procedure begin Writeln('Proc1: ' + i); end; i := 21; SomeProc2 := procedure begin Writeln('Proc2: ' + i); end; SomeProc1; SomeProc2; end; === code end === The output I'd expect here is the following: === output begin === 42 21 === output end === But if I've understood you correctly I'll get the following instead: === output begin === 21 21

BTW closurs in c++ support both cases (capture by value and by reference).

Reply by email