Re: [fpc-devel] Functors

2022-05-26 Thread Sven Barth via fpc-devel

Am 26.12.2021 um 02:16 schrieb Blaise--- via fpc-devel:

Important design points:
1) Applying round brackets to instances does not collide with the 
existing syntax;

2) Naturally, helpers are able to turn helpees into functors;
3) Operator () cannot be applied to types -- that would clash with 
explicit type conversions;
4) Explicit empty argument lists are required -- unorthogonal to 
routines and procedural variables, but clarity must win here;
5) {$modeswitch Closures} is required (modeswitch_closures.patch from 
https://lists.freepascal.org/pipermail/fpc-devel/2021-December/044261.html) 
-- functors are closure-adjacent in the area of functional programming.


The parts that are currently missing:
1) Implicit conversion from functors to method pointers -- should be 
fairly trivial to implement;

2) Support for generics -- should be straightforward as well;
3) The OPERATOR keyword instead of PROCEDURE/FUNCTION for methods 
Invoke -- should we choose to require it -- would be somewhat more 
complicated.


Rejected. I've finally managed to integrate your support for function 
references, more is currently not required.


Regards,
Sven
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Ryan Joseph via fpc-devel


> On Dec 27, 2021, at 1:44 AM, bla...@blaise.ru wrote:
> 
> So, in your book, introducing a /new/ operator identifier "doesn't present 
> any new syntax" (and I agree), but semantically allowing the /existing/ 
> directive DEFAULT to appear in the existing list of method directives is 
> somehow "a new syntax". You have some interesting definition of "syntax".

I was mainly just trying to predict what Sven will say because I've proposed so 
many things over the recent years. :) "Default" has never been used outside of 
properties which is why it could be considered "new syntax".

As for the idea of a "call operator" that would require "self" to be passed in 
as the first param (like record management operators) AND "class operator" is 
not allowed in classes right now so this would limit it to records  only. I 
already tried to get Sven to accept class operators on classes (for some 
operators only) and this was rejected.

Given that I would say this would indeed go the way of properties since it's a 
form of aliasing or re-routing:

  property Invoke: T read DoInvoke; default;

However I have already made a patch (nearly finished) for a "default record 
property" which does something similar to this (it's meant for smart pointers 
like how C++ overloads the -> operator) and even though Sven did seem behind 
the idea I don't see he's been willing to follow up on it. Not sure what this 
means for the feature or if it will ever be accepted.

https://gitlab.com/genericptr/free-pascal/-/tree/default_record_property

So if there is now a default method it would confound this idea even further 
and it's already not clear if FPC will accept this kind of thing.

I'm not saying any of this to discourage the idea though since I think it's 
interesting.

Regards,
Ryan Joseph

___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 27.12.2021 3:14, Martin Frb wrote:

it enables you to skip writing the name of the method that is called?
anything you can do with it, you can already do without it


I am truly flabbergasted at how this could possibly be unclear still. Michael 
have already asked exactly the same questions in the first reply to this 
thread. Allow me to quote my response:
On 26.12.2021 15:40, Blaise--- via fpc-devel wrote:

On 26.12.2021 11:50, Michael Van Canneyt via fpc-devel wrote:

As I see it, it's just shorthand syntax to allow skipping the name 'Invoke'.
None of what is shown below cannot be handled by ordinary methods

Well, yes.



This is what irritates me, if this is a feature, it should enable me to do 
something that otherwise would have been at least some little bit more complex.


I shall go tell Default Array Property and Operator Add that, according to Martin Frb, they have 
been demoted from Features, because "anything he can do with you, he can already do without 
you" and because they need to be a "little bit more complex".


default method


@Michael Van Canneyt: And I rest my case. /You/ never called them "default methods", but, merely based on the 
DEFAULT keyword and syntax similarity, users have already started calling them that -- exactly as I predicted. Then, 
they google "default methods" and they find "default methods in interfaces" for Java and C# -- a 
completely unrelated feature. Yes, the DEFAULT keyword is lying around, readily available, but is it worth the 
confusion of not just inventing a new term for a concept that already has an established name (cf. google "call 
operator overload"), but overloading the established term with an unrelated meaning?

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Martin Frb via fpc-devel

On 27/12/2021 00:18, bla...@blaise.ru wrote:

On 27.12.2021 0:57, Martin Frb via fpc-devel wrote:

writeln( aC(33) );
aC('hello');
the above examples are probably intended to show the syntax. But not 
indented to show any useful application?


The test you quoted demonstrates what is already possible, 
syntactically and semantically, using a simple patch I have extracted 
from my implementation of Closures.


No judgment, but just checking if I missed anything... From the above 
examples, it then is a shortcut?


"shortcut" in the sense that it enables you to skip writing the name of 
the method that is called?
"shortcut" in the sense, that anything you can do with it, you can 
already do without it (and without changing the structure of your code, 
or adding massive amounts of code)?


This is what irritates me, if this is a feature, it should enable me to 
do something that otherwise would have been at least some little bit 
more complex.


Functor and class are (as I understand you) equal in:
- you need to create / destroy them.
- you can store data / add (none default) methods
But different in (and only in?), that a functor has a default method.

Your way to describe it "it can be passed as a function" or "behaves 
like a routine" does not add anything new.

A method / method-reference can do exactly all of that.

As I write this I feel, that I really must be missing some point... I 
just don't see where.
(Sorry for the very repetitive questioning about / just wanted to make 
sure I highlight every angle of my current understanding)





a functor is meant to be ref-counted


A functor is a non-routine entity ("object") that behaves like a 
routine. Meaning: you can invoke it like a routine (via an overloaded 
"operator ()"), you can store it like a routine (in a method pointer). 
That is all, it is quite a simple feature, really. RECORD, OBJECT, 
CLASS, and INTERFACE instances are supported as such entities. With 
these entities, you manage memory as usual.


So basically

type
  TInvoke = procedure of object;

TFunctor = class
  procedure Invoke;
end;

operator := (a: TFunctor): TInvoke;
begin
  result := TInvoke(@a.Invoke);
end;

Only
- I don't need to write the operator by hand, and therefore do not need 
to update the name "invoke" if I change it in the class?
- the above only works in assignments, *not* for directly calling 
"MyFunctor();" (which is where it is a shortcut, to leave out the method 
name)


___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 27.12.2021 0:57, Martin Frb via fpc-devel wrote:

writeln( aC(33) );
aC('hello');

the above examples are probably intended to show the syntax. But not indented 
to show any useful application?


The test you quoted demonstrates what is already possible, syntactically and 
semantically, using a simple patch I have extracted from my implementation of Closures. 
The "missing parts" list recognises that a better syntax for the operator 
declaration is needed, and suggests the keyword OPERATOR. A better syntax was the major 
point of the discussion thus far.


then what in "functor" is a new feature (rather than shortcut)

a functor is meant to be ref-counted


A functor is a non-routine entity ("object") that behaves like a routine. Meaning: you 
can invoke it like a routine (via an overloaded "operator ()"), you can store it like a 
routine (in a method pointer). That is all, it is quite a simple feature, really. RECORD, OBJECT, 
CLASS, and INTERFACE instances are supported as such entities. With these entities, you manage 
memory as usual.

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 27.12.2021 0:03, Michael Van Canneyt via fpc-devel wrote:

On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:

On 26.12.2021 19:33, Michael Van Canneyt via fpc-devel wrote:

On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:

following your reasoning, the same should be said about overloading most of the 
operators: "why is aC+aD better than aC.Add(aD)"?


No. Operators are clearly expressions. ac.Add(aD) is a statement.


How can you tell just from that? :) If Add is a function (which is clearly implied by the 
comparison with the operator Add), then "aC.Add(aD)" is an expression, just like 
"aC+aD".


Well: you write it: IF.
With aC+aD there is no IF, it's an expression. Clear.


I see. I misunderstood your original response. Turns out, you ran with the 
narrowest possible interpretation of my question, which was the condensed 
version of the following:
Given two statements:
1)  A := B + C;
and
2)  A := B.Add(C);
provided they are semantically equivalent -- they both invoke the method Add on 
B with the argument C and store the result in A -- which one do you prefer 
syntactically?


Let me offer another comparison and rephrase my quote: following your reasoning, the same 
should be said about default array properties: "why is aC[42] better than 
aC.Items[42]"?


I would not have introduced this. Delphi has.


But was it, in your book, a bad design decision, violating the principles that 
you outlined earlier?



default interface methods
a dedicated directive
method aliasing

I think you're getting carried away a little ;-) Let's stick to the topic at 
hand


I believe we are firmly on topic. You are criticising Borland for bad design 
decisions; yet, ironically, you seem reluctant to consider as much as possible 
beforehand for this feature, including other possible features and how the subj 
should fit with them.

I am a fan of KISS principle. Hence reusing default, because it is already a keyword. 


Merely FTR: OPERATOR is already a keyword as well. Not employed as directive, 
but still a non-reserved keyword.


Adding the feature is OK, but let's try to keep impact minimal. For me this 
means, reuse 'default' keyword and add an operator.


If you agree on the operator, what do we need the DEFAULT for, especially if we are 
"to keep impact minimal"? Alternative designations, be it a directive or 
routine aliasing, can be introduced later.

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Martin Frb via fpc-devel

On 26/12/2021 02:16, Blaise--- via fpc-devel wrote:
I propose that the support for 
https://en.wikipedia.org/wiki/Function_object be added to the FPC.

...

begin
aC := C.Create;
writeln( aC(33) );
aC('hello');


I might be barging in a bit late. But (within the given set that we have 
/ not within the set of any other language):


Is this a new feature? Or a shortcut? Or maybe more precise, how much of 
it is new.


To start with, the above examples are probably intended to show the 
syntax. But not indented to show any useful application?

Lets go to the example (I think from the wiki).
Passing the functor, instead of a function ref:

  MyList.Sort( C.Create('sort_field') );

This is (mostly) a shortcut for
  MyList.Sort( @C.Create('sort_field').Invoke );


2 things are different in the above.

1) The instance must be ref-counted, and free itself => or you get a mem 
leak.
That part could be regarded as a new feature. Well, actually, my 
understanding is that feature comes under the name of "smart pointer" ? 
(but I may be wrong on that one)


2) Acts as a shortcut.
- removes the  "@"
  which in mode objfpc, really belongs to passing on a reference to 
something that can be called.
  Yes, if it were a class (and therefore a ref by itself), it would not 
be needed, but it is a functor, something that can be called.

- removes the name of the called method.
  Actually a pity. Typing out the name, means the ability to chose a 
diff method, for diff purposes.



So based on this, and
- if "smart pointer" does bring the required ref-count,
- if we do not want to duplicate "smart pointer"
then what in "functor" is a new feature (rather than shortcut), compared 
to the feature already on offer (or under development)?


--
One more question.

If I am right in the assumption, that a functor is meant to be 
ref-counted, then by which criteria is the distinction between "functor" 
and "class" made.


In the example a "functor" is declared as a "class".
But a class is not ref-counted. And changing that for every class is not 
an option, since existing code would not work with this.


So then, how would the compiler know, that a "class" is a "functor" and 
ref counted?


- Because it has an "invoke" function (original suggestion)? (that 
clashes with existing code)

- Because it has a function that has a "default" modifier?
That would be possible, but I think it is not explicit enough.
A simple "default" somewhere on one function, hidden in a list of who 
knows how many functions?


So then, the ref-count would need to go as a modifier to the "class" itself.
Not sure how smart pointers (when used for classes) are to be declared


If I missed anything in the proposal that differs majorly from my 
understanding, then sorry about the noise.

___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Michael Van Canneyt via fpc-devel



On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:


On 26.12.2021 19:33, Michael Van Canneyt via fpc-devel wrote:

On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:

On 26.12.2021 11:50, Michael Van Canneyt via fpc-devel wrote:

None of what is shown below cannot be handled by ordinary methods


Well, yes. But, following your reasoning, the same should be said about 

overloading most of the operators: "why is aC+aD better than aC.Add(aD)"?


No. Operators are clearly expressions. ac.Add(aD) is a statement.


How can you tell just from that? :) If Add is a function (which is clearly 
implied by the comparison with the operator Add), then "aC.Add(aD)" is an 
expression, just like "aC+aD".


Well: you write it: IF.
With aC+aD there is no IF, it's an expression. Clear.



Let me offer another comparison and rephrase my quote: following your 
reasoning, the same should be said about default array properties: "why is 
aC[42] better than aC.Items[42]"?


I would not have introduced this. Delphi has.



with the modern Object Pascal as implemented by DCC and FPC?


I would reject your proposal using Invoke.


Let us be precise here. You mean "procedure/function Invoke", right? Because 
"operator Invoke" (which is part of my proposal) would not clash with other 
entities named Invoke.


procedure/function invoke. How the operator is called, I honestly don't care,
although I would be more in favour of call.





Reusing "default"


As I wrote in my response to Ryan, I actually quite like that, except for one 
reservation: should the support for default interface methods be ever added 
to FPC, the DEFAULT directive would fit there better, IMO.
A dedicated directive would be fine with me, and it could be used to 
designate any compatible method as any operator:

---8<---
type R = record
procedure Foo(...); operator ();
function Bar(const A, B: R): R; operator +;
end;
---8<---

How about another approach, albeit more complex: does FPC support method 
aliasing? Personally, many times, I wished DCC had that.

---8<---
type R = record
procedure Foo(...);
operator () = Foo; // routine alias
// OR: operator Invoke = Foo;
end;
---8<---
Routine aliasing is a more general (hence, more useful) feature on its own; 
and with it, even inherited methods can be designated as operators in derived 
classes.


I think you're getting carried away a little ;-)

Let's stick to the topic at hand:

I am a fan of KISS principle. Hence reusing default, because it is already a
keyword. For every additional keyword, we need to change umpteen routines in
various places. So let's keep that to a minimum.

So I repeat my point of view: Adding the feature is OK, but let's try to keep
impact minimal. For me this means, reuse 'default' keyword and add an operator.
What the name is (call, invoke) does not matter for me...

Michael.
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 26.12.2021 23:47, Blaise--- via fpc-devel wrote:

---8<---
type R = record
 procedure Foo(...); operator ();
 function Bar(const A, B: R): R; operator +;
end;
---8<---


Made a blunder there, sorry: for Bar, it should either be
function Bar(const Other: R): R; operator +;
or
class function Bar(const A, B: R): R; static; operator +;

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 26.12.2021 19:33, Michael Van Canneyt via fpc-devel wrote:

On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:

On 26.12.2021 11:50, Michael Van Canneyt via fpc-devel wrote:

None of what is shown below cannot be handled by ordinary methods


Well, yes. But, following your reasoning, the same should be said about overloading most 
of the operators: "why is aC+aD better than aC.Add(aD)"?


No. Operators are clearly expressions. ac.Add(aD) is a statement.


How can you tell just from that? :) If Add is a function (which is clearly implied by the 
comparison with the operator Add), then "aC.Add(aD)" is an expression, just like 
"aC+aD".

Let me offer another comparison and rephrase my quote: following your reasoning, the same 
should be said about default array properties: "why is aC[42] better than 
aC.Items[42]"?


It should be less confusing if you think of aC as a routine (which is the point 
of Functors). Would aCallback(33) look less confusing?


But it is not a routine. It is a class, and it is declared as one.
Pascal is very explicit about the constructs and classes it uses. It's a 
'Strongly typed language' for a reason.
Blurring the line between functions and classes goes against this, in my 
opinion.


Imagine it is 1995, Delphi introduces default array properties, and my response is: 
"But a class is not an array. It is a class, and it is declared as one. Blurring the 
line between arrays and classes goes against Pascal being a 'Strongly typed language', in 
my opinion."
Even further: "What is this thing -- array property?! It is clearly invoking 
methods behind its back! A method call should not be masquerading as array indexing! 
It is not BASIC, Pascal has different brackets for calls and array indexing for a 
reason!

I understand when you say that you do not find functors useful; that is the 
matter of personal opinion and style. But to say that they are inconsistent 
with the modern Object Pascal as implemented by DCC and FPC?


I would reject your proposal using Invoke.


Let us be precise here. You mean "procedure/function Invoke", right? Because 
"operator Invoke" (which is part of my proposal) would not clash with other entities 
named Invoke.


Reusing "default"


As I wrote in my response to Ryan, I actually quite like that, except for one 
reservation: should the support for default interface methods be ever added to 
FPC, the DEFAULT directive would fit there better, IMO.
A dedicated directive would be fine with me, and it could be used to designate 
any compatible method as any operator:
---8<---
type R = record
procedure Foo(...); operator ();
function Bar(const A, B: R): R; operator +;
end;
---8<---

How about another approach, albeit more complex: does FPC support method 
aliasing? Personally, many times, I wished DCC had that.
---8<---
type R = record
procedure Foo(...);
operator () = Foo; // routine alias
// OR: operator Invoke = Foo;
end;
---8<---
Routine aliasing is a more general (hence, more useful) feature on its own; and 
with it, even inherited methods can be designated as operators in derived 
classes.

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 26.12.2021 17:40, Ryan Joseph via fpc-devel wrote:

I'm 99% certain using the method name "Invoke" would be rejected on the grounds 
of backwards compatibility.


Not to argue for the "procedure/function Invoke" syntax, but it hardly breaks backward 
compatibility. Only in the purest non-practical sense: "I maintain this code that always used 
to be rejected and suddenly it gets compiled".


Adding a new syntax using "default" like "function Add9(const N: Integer): Integer; 
default;"


That is pretty much the /old/ syntax.
I agree with Michael that it would mirror default properties nicely, but:
1) Are we most likely to name that "default method" or "call operator"?
2) We now have proper operator overloading; I would even argue that, were it added to 
Object Pascal much earlier, we would have had "operator Index" instead of 
default array properties;
3) I would rather reserve the DEFAULT directive on methods for default 
interface methods:
---8<---
type I = interface
procedure Foo; default;
// the above, IMO, looks better than
//  procedure Foo; not abstract;
end;
procedure I.Foo; begin { default implementation } end;
---8<---


class operator Call();


Again, the proposal is:
---8<---
type R = record
operator Invoke(...)...;
end;
---8<---
Specifically:
A) without CLASS:
1) Having to declare Self manually would be ridiculous;
2) In interfaces, that method should be instance-virtual.
B) The name Invoke is required for compatibility with DCC.

Granted, for "operator", some hackery would still be required for 100% DCC 
compatibility:
---8<---
type MethRef = reference to procedure;
type C = class(TInterfacedObject, MethRef)
// This needs to map to _operator_ MethRef.Invoke
procedure Invoke;
end;
---8<---


it doesn't present any new syntax


So, in your book, introducing a /new/ operator identifier "doesn't present any new syntax" (and I 
agree), but semantically allowing the /existing/ directive DEFAULT to appear in the existing list of method 
directives is somehow "a new syntax". You have some interesting definition of "syntax".

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Michael Van Canneyt via fpc-devel



On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:


On 26.12.2021 11:50, Michael Van Canneyt via fpc-devel wrote:

Please explain what's the point or benefit of this.


Do you mean "in general", or "specifically to FPC"?

A) In general: I reckon that the article covers the matter quite well; I have 
nothing to add.
B) Specifically for FPC: it is up to the users to decide whether they find 
this useful; I am impartial.


Specifically to FPC.



Personally for me, specifically for FPC, the points are:
1) A variant of that patch is already a part of the Closures -- it makes 
sense to expose that to the users and get another feature (Functors) for 
"half the price";
2) Orthogonality -- I would rather implement a proper feature instead of 
employing a specific "hack" for a single case (translating an interface 
reference into a call).


As I see it, it's just shorthand syntax to allow skipping the name 

'Invoke'.

None of what is shown below cannot be handled by ordinary methods


Well, yes. But, following your reasoning, the same should be said about 
overloading most of the operators: "why is aC+aD better than aC.Add(aD)"?


No. Operators are clearly expressions. ac.Add(aD) is a statement.


I find the resulting code aC(33) more confusing than anything else


It should be less confusing if you think of aC as a routine (which is the 
point of Functors). Would aCallback(33) look less confusing?


But it is not a routine. It is a class, and it is declared as one.

Pascal is very explicit about the constructs and classes it uses. 
It's a 'Strongly typed language' for a reason.


Blurring the line between functions and classes goes against this, in my
opinion.



I think the idea is overly complicated and can be achieved simply by the 

mechanism used by default array properties:

    function Add9(const N: Integer): Integer; default;


That could be an alternative /syntax/ for denoting the special method, but I 
do not see how that would "uncomplicate" the /idea/. To me, that is exactly 
the same idea with the same level of complication.


I was strictly speaking of syntax. 
The idea: I personally don't see the use, but that does not mean I would torpedo the idea.




Likewise, conceptually, "default array properties" /is/ "operator []" with a 
clunkier syntax and a benefit of being able to access such property by name.


We clearly disagree on what constitutes a clunkier syntax.

I would reject your proposal using Invoke.

Reusing "default" - it's just reusing an existing keyword as another modifier 
for methods.
The impact on syntax is negligible.

It also leaves you free to choose your identifiers. For backwards compatibility
alone the use of Invoke is a bad idea, specially since the RTTI invoke method
is prominently a part of RTTI.

As a second option the "call operator" would be acceptable. 
So from my perspective these are OK (one or both):


- Allow use of default
- Introduce 'Call' operator.

For me, the use of a specific method name is not acceptable for backwards 
compatibility.

Michael.
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Michael Van Canneyt via fpc-devel



On Sun, 26 Dec 2021, Ryan Joseph via fpc-devel wrote:





On Dec 26, 2021, at 3:50 PM, Michael Van Canneyt via fpc-devel 
 wrote:

I think the idea of using a fixed member identifier for special purposes is 
really
stupid design. I'll never forgive Embarcadero their 'GetEnumerator' idea...


I'm 99% certain using the method name "Invoke" would be rejected on the grounds 
of backwards compatibility.

Adding a new syntax using "default" like "function Add9(const N: Integer):
Integer; default;" would probably  be rejected on the grounds that it's
new syntax alone (that is default is only used with properties currently).


Why ? I'm proposing it. As far as I'm concerned, it is the way to go.

You could use it to easily promote a method to default on existing calls.

Michael.
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Ryan Joseph via fpc-devel


> On Dec 26, 2021, at 3:50 PM, Michael Van Canneyt via fpc-devel 
>  wrote:
> 
> Please explain what's the point or benefit of this.

To aid in the usage of classes that have the sole intent of being called. 
Surely though the compiler team will say this is not *needed* and can be 
achieved using normal method calls.

Question to Blaise, how is this adjacent to closures? I just see it as an 
operator overload, i.e. how C++ allows to overload the () operator.

I will also say In my attempt to make a "default property" which could be used 
for smart pointers Sven specially said absolutely no to the idea of overloading 
the "." operator so I tend to think this idea won't go far.

Regards,
Ryan Joseph

___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Ryan Joseph via fpc-devel


> On Dec 26, 2021, at 3:50 PM, Michael Van Canneyt via fpc-devel 
>  wrote:
> 
> I think the idea of using a fixed member identifier for special purposes is 
> really
> stupid design. I'll never forgive Embarcadero their 'GetEnumerator' idea...

I'm 99% certain using the method name "Invoke" would be rejected on the grounds 
of backwards compatibility.

Adding a new syntax using "default" like "function Add9(const N: Integer): 
Integer; default;" would probably  be rejected on the grounds that it's new 
syntax alone (that is default is only used with properties currently).

I would say an operator would be most likely to be accepted, such as:

class operator Call();

because it could be overloaded easily and doesn't present any new syntax.

Personally I like this idea but I tend to favor new syntaxes.

Regards,
Ryan Joseph

___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Blaise--- via fpc-devel

On 26.12.2021 11:50, Michael Van Canneyt via fpc-devel wrote:

Please explain what's the point or benefit of this.


Do you mean "in general", or "specifically to FPC"?

A) In general: I reckon that the article covers the matter quite well; I have 
nothing to add.
B) Specifically for FPC: it is up to the users to decide whether they find this 
useful; I am impartial.

Personally for me, specifically for FPC, the points are:
1) A variant of that patch is already a part of the Closures -- it makes sense to expose 
that to the users and get another feature (Functors) for "half the price";
2) Orthogonality -- I would rather implement a proper feature instead of employing a 
specific "hack" for a single case (translating an interface reference into a 
call).


As I see it, it's just shorthand syntax to allow skipping the name 'Invoke'.
None of what is shown below cannot be handled by ordinary methods


Well, yes. But, following your reasoning, the same should be said about overloading most 
of the operators: "why is aC+aD better than aC.Add(aD)"?


I find the resulting code aC(33) more confusing than anything else


It should be less confusing if you think of aC as a routine (which is the point 
of Functors). Would aCallback(33) look less confusing?


I think the idea is overly complicated and can be achieved simply by the 
mechanism used by default array properties:
    function Add9(const N: Integer): Integer; default;


That could be an alternative /syntax/ for denoting the special method, but I do not see 
how that would "uncomplicate" the /idea/. To me, that is exactly the same idea 
with the same level of complication.

Likewise, conceptually, "default array properties" /is/ "operator []" with a 
clunkier syntax and a benefit of being able to access such property by name.


I think the idea of using a fixed member identifier for special purposes is 
really stupid design.


I would agree in general, but you did see that using the OPERATOR keyword is 
part of the proposal, right?
"operator Add" is not necessarily worse than "operator +".

--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


Re: [fpc-devel] Functors

2021-12-26 Thread Michael Van Canneyt via fpc-devel



On Sun, 26 Dec 2021, Blaise--- via fpc-devel wrote:

I propose that the support for https://en.wikipedia.org/wiki/Function_object 
be added to the FPC.


Please explain what's the point or benefit of this.

None of what is shown below cannot be handled by ordinary methods, and I
find the resulting code aC(33) more confusing than anything else.

As I see it, it's just shorthand syntax to allow skipping the name 'Invoke'.

If that is all it is, then I think the idea is overly complicated and can be
achieved simply by the mechanism used by default array properties:

To reuse your example:
Type
 C = class(TObject)
   function Add9(const N: Integer): Integer; default;
 end;

var
  aC : C;

begin
  aC:=C.Create;
  Writeln(ac(33));
end;

I think the idea of using a fixed member identifier for special purposes is 
really
stupid design. I'll never forgive Embarcadero their 'GetEnumerator' idea...

Michael.





A subset of such functionality already existed as a part of my implementation 
of closures, so I extended that part to implement the core feature for 
allowing functors -- overloading of the call operator: when round brackets 
are applied to an instance of a record, object/class, or interface type, they 
are translated into a call to the method Invoke of that instance. The 
attached proof-of-concept functors-1.patch allows the following test case to 
be compiled:

---8<---
type I = interface
procedure Invoke;
end;

type C = class(TInterfacedObject, I)
class function Invoke(const N: Integer): Integer; overload;
procedure Invoke; overload;
end;
class function C.Invoke(const N: Integer): Integer;
begin
result := N + 9
end;
procedure C.Invoke;
begin
writeln(ClassName, '.Invoke')
end;

type H = class helper for C
procedure Invoke(const S: string); overload;
end;
procedure H.Invoke(const S: string);
begin
writeln('H.Invoke("', S, '")')
end;

var aC: C;
var anI: I;
begin
aC := C.Create;
writeln( aC(33) );
aC('hello');

anI := aC;
anI()
end.
---8<---
Important design points:
1) Applying round brackets to instances does not collide with the existing 
syntax;

2) Naturally, helpers are able to turn helpees into functors;
3) Operator () cannot be applied to types -- that would clash with explicit 
type conversions;
4) Explicit empty argument lists are required -- unorthogonal to routines and 
procedural variables, but clarity must win here;
5) {$modeswitch Closures} is required (modeswitch_closures.patch from 
https://lists.freepascal.org/pipermail/fpc-devel/2021-December/044261.html) 
-- functors are closure-adjacent in the area of functional programming.


The parts that are currently missing:
1) Implicit conversion from functors to method pointers -- should be fairly 
trivial to implement;

2) Support for generics -- should be straightforward as well;
3) The OPERATOR keyword instead of PROCEDURE/FUNCTION for methods Invoke -- 
should we choose to require it -- would be somewhat more complicated.


--
βþ
___
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel


[fpc-devel] Functors

2021-12-25 Thread Blaise--- via fpc-devel

I propose that the support for https://en.wikipedia.org/wiki/Function_object be 
added to the FPC.

A subset of such functionality already existed as a part of my implementation 
of closures, so I extended that part to implement the core feature for allowing 
functors -- overloading of the call operator: when round brackets are applied 
to an instance of a record, object/class, or interface type, they are 
translated into a call to the method Invoke of that instance. The attached 
proof-of-concept functors-1.patch allows the following test case to be compiled:
---8<---
type I = interface
procedure Invoke;
end;

type C = class(TInterfacedObject, I)
class function Invoke(const N: Integer): Integer; overload;
procedure Invoke; overload;
end;
class function C.Invoke(const N: Integer): Integer;
begin
result := N + 9
end;
procedure C.Invoke;
begin
writeln(ClassName, '.Invoke')
end;

type H = class helper for C
procedure Invoke(const S: string); overload;
end;
procedure H.Invoke(const S: string);
begin
writeln('H.Invoke("', S, '")')
end;

var aC: C;
var anI: I;
begin
aC := C.Create;
writeln( aC(33) );
aC('hello');

anI := aC;
anI()
end.
---8<---
Important design points:
1) Applying round brackets to instances does not collide with the existing 
syntax;
2) Naturally, helpers are able to turn helpees into functors;
3) Operator () cannot be applied to types -- that would clash with explicit 
type conversions;
4) Explicit empty argument lists are required -- unorthogonal to routines and 
procedural variables, but clarity must win here;
5) {$modeswitch Closures} is required (modeswitch_closures.patch from 
https://lists.freepascal.org/pipermail/fpc-devel/2021-December/044261.html) -- 
functors are closure-adjacent in the area of functional programming.

The parts that are currently missing:
1) Implicit conversion from functors to method pointers -- should be fairly 
trivial to implement;
2) Support for generics -- should be straightforward as well;
3) The OPERATOR keyword instead of PROCEDURE/FUNCTION for methods Invoke -- 
should we choose to require it -- would be somewhat more complicated.

--
βþ
# HG changeset patch
# User Blaise.ru
# Date 1640402948 -10800
#  Sat Dec 25 06:29:08 2021 +0300
+ Functors: applying round brackets to instances calls their method Invoke

diff -r 3ecaef5e9a49 -r 0ac7231ddc94 pexpr.pas
--- a/pexpr.pas Sat Dec 25 21:36:11 2021 +0300
+++ b/pexpr.pas Sat Dec 25 06:29:08 2021 +0300
@@ -2762,45 +2762,73 @@
 
   else
 begin
-  { is this a procedure variable ? }
-  if assigned(p1.resultdef) and
- (p1.resultdef.typ=procvardef) then
-begin
-  { Typenode for typecasting or expecting a procvar }
-  if (p1.nodetype=typen) or
- (
-  assigned(getprocvardef) and
-  equal_defs(p1.resultdef,getprocvardef)
- ) then
+  if assigned(p1.resultdef) then
+case p1.resultdef.typ of
+  { a procedural variable }
+  procvardef:
 begin
-  if try_to_consume(_LKLAMMER) then
+  { Typenode for typecasting or expecting a procvar }
+  if (p1.nodetype=typen) or
+ (
+  assigned(getprocvardef) and
+  equal_defs(p1.resultdef,getprocvardef)
+ ) then
 begin
-  p1:=comp_expr([ef_accept_equal]);
-  consume(_RKLAMMER);
-  p1:=ctypeconvnode.create_explicit(p1,p1.resultdef);
+  if try_to_consume(_LKLAMMER) then
+begin
+  p1:=comp_expr([ef_accept_equal]);
+  consume(_RKLAMMER);
+  
p1:=ctypeconvnode.create_explicit(p1,p1.resultdef);
+end
+  else
+again:=false
 end
   else
-again:=false
-end
+begin
+  if try_to_consume(_LKLAMMER) then
+begin
+  p2:=parse_paras(false,false,_RKLAMMER);
+  consume(_RKLAMMER);
+  p1:=ccallnode.create_procvar(p2,p1);
+  { proc():= is never possible }
+  if token=_ASSIGNMENT then
+begin
+  Message(parser_e_illegal_expression);
+  p1.free;
+