Re: [PHP-DEV] [RFC] First-class callable syntax

2021-06-29 Thread Olle Härstedt
2021-05-20 14:48 GMT+02:00, Nikita Popov :
> Hi internals,
>
> I'd like to present an RFC for a first-class callable syntax, which is
> intended as a simpler alternative to the partial function application (PFA)
> proposal:
>
> https://wiki.php.net/rfc/first_class_callable_syntax
>
> See the Rationale section for details on how this relates to PFA. Over the
> past week, we've had a lot of discussions on how exactly PFA is supposed to
> work (most of them OTR), and while we seem to have a tentative consensus on
> the correct model to use (which does not match the current RFC), it's clear
> that this feature has turned out more complicated than originally
> anticipated. Joe (who provided the implementation for the PFA RFC) is also
> concerned about the implementation complexity that the final model would
> require.
>
> At least I personally was mainly interested in PFA because it provides a
> first-class callable syntax as a side-effect. This RFC goes back to
> providing *just* that. The syntax is forward-compatible with a future PFA
> proposal though.
>
> Regards,
> Nikita

More bikeshedding, sorry. Was a syntax using `fn` considered? Like

$fn = Closure::fromCallable('strlen');
$fn = fn strlen;

or

$fn = (fn) strlen;

Olle

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-25 Thread Guilliam Xavier
On Fri, May 21, 2021 at 10:08 AM Rowan Tommins 
wrote:

>
> Everyone: please let's keep this thread for talking about first-class
> callables, and focus on the semantics not just the syntax - are there
> edge cases we need to consider, downsides to the proposed
> implementation, etc?
>

Well the semantics seem rather clear? We could say one "downside" is that
new-expressions are not supported, but the RFC explains why (
https://wiki.php.net/rfc/first_class_callable_syntax#object_creation, I
think it makes sense), and special-casing can always be added later (or in
PFA).

Regards,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-25 Thread Guilliam Xavier
On Fri, May 21, 2021 at 11:09 AM Andreas Leathley 
wrote:

> [...]
>
> About the bikeshedding: Using "..." as a symbol does make sense to me,
> as variadic unpacking/variadic arguments have a similar connotation
> (referring to an unknown/arbitrary amount of elements). * was also
> suggested (as in "somefunction(*)" instead of "somefunction(...)"), and
> I like that too - * in regex is any amount of elements (even zero), and
> ? is exactly one placeholder in SQL. As many PHP developers know regex
> and SQL this would make PFA code a lot easier to understand even if
> someone is not that familiar with it yet.
>

FWIW: In this context, ? and * remind me of shell wildcards (used by glob()
and fnmatch()), which makes sense too.
Also, at least one person is opposed to "...".

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-25 Thread Nicolas Grekas
Le ven. 21 mai 2021 à 16:31, Larry Garfield  a
écrit :

> On Fri, May 21, 2021, at 2:52 AM, Nicolas Grekas wrote:
> > Sorry for self-reply, this needs some clarifications :)
> >
> > Le ven. 21 mai 2021 à 09:17, Nicolas Grekas <
> nicolas.grekas+...@gmail.com>
> > a écrit :
>
>
> > >> There's been a lot of rapid iteration, experimentation, and rejection.
> > >> The most recent alternatives are this one from Levi:
> > >>
> > >> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd
> > >>
> > >> And this one from me:
> > >>
> > >> https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8
> > >>
> > >> The main takeaways (to give context to Nikita's proposal):
> > >>
> > >> * Because of optional arguments, using the same symbol for "copy one
> > >> parameter from the underlying function" and "copy all remaining
> parameters
> > >> from the underlying function" is not viable.  It runs into oddball
> cases
> > >> where you may intend to only use one argument but end up using
> multiple,
> > >> especially in array operation functions that sometimes silently pass
> keys
> > >> along to callbacks if they can.  Hence the separate ? and ... that
> were
> > >> proposed.
> > >>
> > >
> > > I've read that some ppl think this should be fought, but that's
> actually a
> > > critical feature of the engine when writing BC layers by adding extra
> > > arguments via this possibility.
> > >
> >
> > I'm talking about implicit extra arguments accessed via func_get_args()
> > here.
>
> The issue is with optional arguments that would get auto-forwarded, even
> when you don't want to use them.  (It wasn't obvious to me for a long time
> that this issue existed either.)  The classic example, ported from
> Javascript:
>
> function printInt(string $value, int $base = 10): void
> {
> echo intval($value, $base), "\n";
> }
>
> $array = ['10', '10', '10', '10', '10'];
>
> array_walk($array, 'printInt');
>
> Results in:
>
> 10
> 0
> 2
> 3
> 4
>
> The function has multiple arguments, but we only want to use one, but
> functions like array_walk() will try to use  the optional one if they
> can... even if doing so makes no logical sense.  Having ? capture all
> arguments unconditionally would also mean it captures optional arguments
> even if you don't want it to.  That's why we need to have the separate ...
> symbol for when you really do mean "and all the rest".
>

Got it thanks. Makes sense to me now.

In this case, we need printInt(?) to only pass $value through.  If you
> really did want to use the array key for the base for some reason, you
> could do printInt(?, ?) or printInt(...).
>
> I think the plan would be that extra passed arguments to a partialed
> function would still forward through, but that may end up being more
> difficult than expected.
>
> > In the 2nd gist, I read "If the current position is a ..., copy all
> > > remaining parameters from the underlying function, including a
> variadic."
> > > But to me it's important that all extra arguments are forwarded to the
> > > partialized callable, where ... is used or not.
> > > Please clarify this point if possible.
>
> I think this is the same as the previous question?
>
> (Note that several vocal people have argued that the way PHP passes along
> extraneous arguments is a bug, not a feature.  I don't have a strong
> feeling about it, but some do.)
>

Being vocal doesn't mean being right :)
This feature of the language is critical to write BC layers, see eg this,
LSP rulez:
https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php#L38

It has to stay (unless an alternative is provided of course.)


> > * Named arguments make things more complicated.  One of the questions is
> > >> whether named placeholders should be supported or not.  And if they
> are,
> > >> does that mean you can effectively reorder the arguments in the
> partial
> > >> application, and what does that mean for usability.  It gets
> complicated
> > >> and scope-creepy fast.
> > >>
> > >
> > > For the userland pov, the principle of least surprise would say we
> should
> > > answer yes to both questions.
> >
> > Reading your gists, I'm with drawing this expectation.
> >
> > Since calls reorder named arguments automatically, we could expect the
> same
> > for PFAs.
> > That is:
> > since foo(A: 1, B: 2) is exactly the same as foo(B: 2, A: 1)
> > we could also expect that foo(A: ?, B: ?) would be exactly the same
> > foo(B:?, A:?)
> >
> > The issue here is that the syntax can be interpreted as both a new
> > signature and as a partial call.
> > If we stay pure to the intend of PFAs, argument reordering shouldn't be
> > allowed IMHO. Aka this should be interpreted only as a partial call.
> >
> > *If* we need a way to reorder arguments, I think it would be natural also
> > to be able to *rename* arguments.
>
> Which is also where the rabbit hole gets extra deep, and why I am
> perfectly happy to just disallow named 

Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-21 Thread Larry Garfield
On Fri, May 21, 2021, at 2:52 AM, Nicolas Grekas wrote:
> Sorry for self-reply, this needs some clarifications :)
> 
> Le ven. 21 mai 2021 à 09:17, Nicolas Grekas 
> a écrit :


> >> There's been a lot of rapid iteration, experimentation, and rejection.
> >> The most recent alternatives are this one from Levi:
> >>
> >> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd
> >>
> >> And this one from me:
> >>
> >> https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8
> >>
> >> The main takeaways (to give context to Nikita's proposal):
> >>
> >> * Because of optional arguments, using the same symbol for "copy one
> >> parameter from the underlying function" and "copy all remaining parameters
> >> from the underlying function" is not viable.  It runs into oddball cases
> >> where you may intend to only use one argument but end up using multiple,
> >> especially in array operation functions that sometimes silently pass keys
> >> along to callbacks if they can.  Hence the separate ? and ... that were
> >> proposed.
> >>
> >
> > I've read that some ppl think this should be fought, but that's actually a
> > critical feature of the engine when writing BC layers by adding extra
> > arguments via this possibility.
> >
> 
> I'm talking about implicit extra arguments accessed via func_get_args()
> here.

The issue is with optional arguments that would get auto-forwarded, even when 
you don't want to use them.  (It wasn't obvious to me for a long time that this 
issue existed either.)  The classic example, ported from Javascript:

function printInt(string $value, int $base = 10): void
{
echo intval($value, $base), "\n";
}

$array = ['10', '10', '10', '10', '10'];

array_walk($array, 'printInt');

Results in:

10
0
2
3
4

The function has multiple arguments, but we only want to use one, but functions 
like array_walk() will try to use  the optional one if they can... even if 
doing so makes no logical sense.  Having ? capture all arguments 
unconditionally would also mean it captures optional arguments even if you 
don't want it to.  That's why we need to have the separate ... symbol for when 
you really do mean "and all the rest".

In this case, we need printInt(?) to only pass $value through.  If you really 
did want to use the array key for the base for some reason, you could do 
printInt(?, ?) or printInt(...).

I think the plan would be that extra passed arguments to a partialed function 
would still forward through, but that may end up being more difficult than 
expected.  

> In the 2nd gist, I read "If the current position is a ..., copy all
> > remaining parameters from the underlying function, including a variadic."
> > But to me it's important that all extra arguments are forwarded to the
> > partialized callable, where ... is used or not.
> > Please clarify this point if possible.

I think this is the same as the previous question?

(Note that several vocal people have argued that the way PHP passes along 
extraneous arguments is a bug, not a feature.  I don't have a strong feeling 
about it, but some do.)

> > * Named arguments make things more complicated.  One of the questions is
> >> whether named placeholders should be supported or not.  And if they are,
> >> does that mean you can effectively reorder the arguments in the partial
> >> application, and what does that mean for usability.  It gets complicated
> >> and scope-creepy fast.
> >>
> >
> > For the userland pov, the principle of least surprise would say we should
> > answer yes to both questions.
> 
> Reading your gists, I'm with drawing this expectation.
> 
> Since calls reorder named arguments automatically, we could expect the same
> for PFAs.
> That is:
> since foo(A: 1, B: 2) is exactly the same as foo(B: 2, A: 1)
> we could also expect that foo(A: ?, B: ?) would be exactly the same
> foo(B:?, A:?)
> 
> The issue here is that the syntax can be interpreted as both a new
> signature and as a partial call.
> If we stay pure to the intend of PFAs, argument reordering shouldn't be
> allowed IMHO. Aka this should be interpreted only as a partial call.
> 
> *If* we need a way to reorder arguments, I think it would be natural also
> to be able to *rename* arguments.

Which is also where the rabbit hole gets extra deep, and why I am perfectly 
happy to just disallow named placeholders.  In the rare use cases where you 
really do want/need to reorder arguments and do other esoteric things, short 
lambdas already let you do that much more explicitly.  That's an edge case that 
already has a solution.  We're focused here on making the most common cases 
nicer.

> That's where my syntax proposal based on short closures might be handy:
> 
> fn($a, $b, ...) => $callable($b, a: $a, ...)

At that point we're not getting any benefit over just using arrow functions.  
The point of PFA is that it's partially calling a function as-is, in a compact 
way.  That in PHP we'd be implementing it as yet-another-closure object is an 

Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-21 Thread Andreas Leathley

On 20.05.21 21:35, Larry Garfield wrote:

There's been a lot of rapid iteration, experimentation, and rejection.
The most recent alternatives are this one from Levi:
https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd

And this one from me:

https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8

The main takeaways (to give context to Nikita's proposal):

* Because of optional arguments, using the same symbol for "copy one parameter from the 
underlying function" and "copy all remaining parameters from the underlying 
function" is not viable.  It runs into oddball cases where you may intend to only use one 
argument but end up using multiple, especially in array operation functions that sometimes silently 
pass keys along to callbacks if they can.  Hence the separate ? and ... that were proposed.

* Named arguments make things more complicated.  One of the questions is 
whether named placeholders should be supported or not.  And if they are, does 
that mean you can effectively reorder the arguments in the partial application, 
and what does that mean for usability.  It gets complicated and scope-creepy 
fast.

* The most important use cases are:
** "prefill nothing, just give me a callable" (which is the case Nikita's RFC 
covers)
** "reduce an arbitrary function to a single remaining argument", which lets it 
be used by various existing callback functions in the standard library (array_map, 
array_filter, etc.), many user-space APIs, and the pipes RFC that I am planning to bring 
back up once PFA is figured out (https://wiki.php.net/rfc/pipe-operator-v2).

While there are other use cases, the two of those cover the vast majority of 
uses.  (There is some dispute about which of those is larger, or will be larger 
in the future.)

It took a while to realize the first point, which basically killed "? means zero or 
more".  We also went down a rabbit hole of trying to make argument reordering work 
because some people asked for it, but as noted that's a very deep rabbit hole.

My gist above was a reduced-scope version of Levi's that uses two symbols and 
drops named placeholders.  It doesn't give us every possible combination, but 
it does give us most reasonable combinations.

Nikita's "just do the first one" RFC (this thread) was proposed at about the 
same time, and takes an even-further scope reduction.

My own take is that the PFA discussion has been overly-bikeshedded, which is unfortunate 
since I think we're quite close to now having a workable answer that covers most 
reasonable use cases.  While I agree Nikita's RFC here would be an improvement over 8.0, 
I don't think throwing in the towel on PFA yet is a good idea.  It's a much more robust 
and powerful approach that still gets us the "first class callable" syntax we 
all want (at least I assume we all do), and lots of additional power to boot.  I'd rather 
see us try to drive PFA home to completion.  If that proves impossible by early July, 
then this RFC would still get us something this cycle, as long as the syntax is still 
compatible with PFA.  (Otherwise whenever PFA gets sorted out in the future we end up 
with yet-more-ways to do the same thing that are not optimizations of each other but just 
competing syntax, in which case no one wins.)


I think Levis proposal and the two symbols ... and ? are a really good
improvement to the previous PFA RFC (Nikitas/Joes RFC is a good first
step in that direction). I do think named arguments are important, but
reordering arguments could be confusing and are not necessary (and if
named arguments are used for the PFA, it would make sense to use named
arguments for calling it too).

Another big reason for me why I like Levis proposal more is that he
still includes partially applying the new operator. Although the
semantics of the new operator are a bit different from regular
functions, it would be very handy to support this special case.
array_map is an obvious application:

$productObjects = array_map(new Product(?, ?, ?), $productIds,
$currencies, $prices);

But other usages would probably pop up, like abstracting away
dependencies of classes by pre-setting those via PFA, like:

$productFactory = new Product($dependency1, $dependency2, ...);
$productObjects = array_map($productFactory, $productIds, $currencies,
$prices);

I really like this because from a users perspective this seems very
clear and readable to me, even though from the PHP language perspective
it might be more messy.

About the bikeshedding: Using "..." as a symbol does make sense to me,
as variadic unpacking/variadic arguments have a similar connotation
(referring to an unknown/arbitrary amount of elements). * was also
suggested (as in "somefunction(*)" instead of "somefunction(...)"), and
I like that too - * in regex is any amount of elements (even zero), and
? is exactly one placeholder in SQL. As many PHP developers know regex
and SQL this would make PFA code a lot easier to understand even if
someone is 

Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-21 Thread Rowan Tommins

On 20/05/2021 23:58, David Gebler wrote:

I think this is very sensible, I can only really say I'd rather have
Nikita's proposal land in 8.1 and PFAs in 9.0 done right than have PFAs in
8.1 but in a way which is confusing, ambiguous or problematic for users, or
not covering reasonable expected use cases.



I wholeheartedly agree with this sentiment. I hope it doesn't take until 
9.0, but if we get first-class callables in 8.1 and partial application 
in 8.2 those are BOTH huge new features.


And if by some miracle we come up with the perfect version of PFA a week 
after this RFC passes, that's ALSO great.



Everyone: please let's keep this thread for talking about first-class 
callables, and focus on the semantics not just the syntax - are there 
edge cases we need to consider, downsides to the proposed 
implementation, etc?



Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-21 Thread Nicolas Grekas
Sorry for self-reply, this needs some clarifications :)

Le ven. 21 mai 2021 à 09:17, Nicolas Grekas 
a écrit :

> Thank you all for your efforts, I think we're almost there and that PFA
> would be a really great and useful addition to the language.
>
> Le jeu. 20 mai 2021 à 21:38, Larry Garfield  a
> écrit :
>
>> On Thu, May 20, 2021, at 10:55 AM, Guilliam Xavier wrote:
>> > On Thu, May 20, 2021 at 5:12 PM Nikita Popov 
>> wrote:
>> >
>> > > On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes 
>> wrote:
>> > >
>> > > > Hi, I’m confused by the syntax, when I read it, I think to myself
>> “I know
>> > > > this, this is just a method call… oh wait, it’s actually a
>> callable”. It
>> > > > really makes my head hurt.
>> > > >
>> > >
>> > > Yes, I can see how that could be confusing. The current syntax is
>> chosen to
>> > > be a subset of the partial function application proposal. However, I
>> would
>> > > also be happy with some other syntax that makes it clearer that this
>> is
>> > > acquiring a callable and not performing a call.
>> > >
>> >
>> > Hi, several other syntaxes have been proposed to consideration in the
>> PFA
>> > thread, and I wouldn't want to start new bikeshedding here; is there a
>> > place that would be more appropriate to gather the possibilities (like a
>> > kind of updatable list)?
>> >
>> > Thanks,
>>
>> There's been a lot of rapid iteration, experimentation, and rejection.
>> The most recent alternatives are this one from Levi:
>>
>> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd
>>
>> And this one from me:
>>
>> https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8
>>
>> The main takeaways (to give context to Nikita's proposal):
>>
>> * Because of optional arguments, using the same symbol for "copy one
>> parameter from the underlying function" and "copy all remaining parameters
>> from the underlying function" is not viable.  It runs into oddball cases
>> where you may intend to only use one argument but end up using multiple,
>> especially in array operation functions that sometimes silently pass keys
>> along to callbacks if they can.  Hence the separate ? and ... that were
>> proposed.
>>
>
> I've read that some ppl think this should be fought, but that's actually a
> critical feature of the engine when writing BC layers by adding extra
> arguments via this possibility.
>

I'm talking about implicit extra arguments accessed via func_get_args()
here.

In the 2nd gist, I read "If the current position is a ..., copy all
> remaining parameters from the underlying function, including a variadic."
> But to me it's important that all extra arguments are forwarded to the
> partialized callable, where ... is used or not.
> Please clarify this point if possible.
>
> * Named arguments make things more complicated.  One of the questions is
>> whether named placeholders should be supported or not.  And if they are,
>> does that mean you can effectively reorder the arguments in the partial
>> application, and what does that mean for usability.  It gets complicated
>> and scope-creepy fast.
>>
>
> For the userland pov, the principle of least surprise would say we should
> answer yes to both questions.
>

Reading your gists, I'm with drawing this expectation.

Since calls reorder named arguments automatically, we could expect the same
for PFAs.
That is:
since foo(A: 1, B: 2) is exactly the same as foo(B: 2, A: 1)
we could also expect that foo(A: ?, B: ?) would be exactly the same
foo(B:?, A:?)

The issue here is that the syntax can be interpreted as both a new
signature and as a partial call.
If we stay pure to the intend of PFAs, argument reordering shouldn't be
allowed IMHO. Aka this should be interpreted only as a partial call.

*If* we need a way to reorder arguments, I think it would be natural also
to be able to *rename* arguments.

That's where my syntax proposal based on short closures might be handy:

fn($a, $b, ...) => $callable($b, a: $a, ...)



>
>
>> We also went down a rabbit hole of trying to make argument reordering
>> work because some people asked for it, but as noted that's a very deep
>> rabbit hole.
>>
>
> Then maybe named args should be forbidden for "?" placeholders. This would
> keep this possibility open of the future and close the "principle of least
> surprise" expectation if there are. Aka foo(bar: ?) should be a parse error
> for now at least.
>
> My own take is that the PFA discussion has been overly-bikeshedded, which
>> is unfortunate since I think we're quite close to now having a workable
>> answer that covers most reasonable use cases.  While I agree Nikita's RFC
>> here would be an improvement over 8.0, I don't think throwing in the towel
>> on PFA yet is a good idea.  It's a much more robust and powerful approach
>> that still gets us the "first class callable" syntax we all want (at least
>> I assume we all do), and lots of additional power to boot.  I'd rather see
>> us try to drive PFA home to completion.  If that proves 

Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-21 Thread Nicolas Grekas
Thank you all for your efforts, I think we're almost there and that PFA
would be a really great and useful addition to the language.

Le jeu. 20 mai 2021 à 21:38, Larry Garfield  a
écrit :

> On Thu, May 20, 2021, at 10:55 AM, Guilliam Xavier wrote:
> > On Thu, May 20, 2021 at 5:12 PM Nikita Popov 
> wrote:
> >
> > > On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes 
> wrote:
> > >
> > > > Hi, I’m confused by the syntax, when I read it, I think to myself “I
> know
> > > > this, this is just a method call… oh wait, it’s actually a
> callable”. It
> > > > really makes my head hurt.
> > > >
> > >
> > > Yes, I can see how that could be confusing. The current syntax is
> chosen to
> > > be a subset of the partial function application proposal. However, I
> would
> > > also be happy with some other syntax that makes it clearer that this is
> > > acquiring a callable and not performing a call.
> > >
> >
> > Hi, several other syntaxes have been proposed to consideration in the PFA
> > thread, and I wouldn't want to start new bikeshedding here; is there a
> > place that would be more appropriate to gather the possibilities (like a
> > kind of updatable list)?
> >
> > Thanks,
>
> There's been a lot of rapid iteration, experimentation, and rejection.
> The most recent alternatives are this one from Levi:
>
> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd
>
> And this one from me:
>
> https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8
>
> The main takeaways (to give context to Nikita's proposal):
>
> * Because of optional arguments, using the same symbol for "copy one
> parameter from the underlying function" and "copy all remaining parameters
> from the underlying function" is not viable.  It runs into oddball cases
> where you may intend to only use one argument but end up using multiple,
> especially in array operation functions that sometimes silently pass keys
> along to callbacks if they can.  Hence the separate ? and ... that were
> proposed.
>

I've read that some ppl think this should be fought, but that's actually a
critical feature of the engine when writing BC layers by adding extra
arguments via this possibility.

In the 2nd gist, I read "If the current position is a ..., copy all
remaining parameters from the underlying function, including a variadic."
But to me it's important that all extra arguments are forwarded to the
partialized callable, where ... is used or not.
Please clarify this point if possible.

* Named arguments make things more complicated.  One of the questions is
> whether named placeholders should be supported or not.  And if they are,
> does that mean you can effectively reorder the arguments in the partial
> application, and what does that mean for usability.  It gets complicated
> and scope-creepy fast.
>

For the userland pov, the principle of least surprise would say we should
answer yes to both questions.


> We also went down a rabbit hole of trying to make argument reordering work
> because some people asked for it, but as noted that's a very deep rabbit
> hole.
>

Then maybe named args should be forbidden for "?" placeholders. This would
keep this possibility open of the future and close the "principle of least
surprise" expectation if there are. Aka foo(bar: ?) should be a parse error
for now at least.

My own take is that the PFA discussion has been overly-bikeshedded, which
> is unfortunate since I think we're quite close to now having a workable
> answer that covers most reasonable use cases.  While I agree Nikita's RFC
> here would be an improvement over 8.0, I don't think throwing in the towel
> on PFA yet is a good idea.  It's a much more robust and powerful approach
> that still gets us the "first class callable" syntax we all want (at least
> I assume we all do), and lots of additional power to boot.  I'd rather see
> us try to drive PFA home to completion.  If that proves impossible by early
> July, then this RFC would still get us something this cycle, as long as the
> syntax is still compatible with PFA.  (Otherwise whenever PFA gets sorted
> out in the future we end up with yet-more-ways to do the same thing that
> are not optimizations of each other but just competing syntax, in which
> case no one wins.)
>

I agree. Let's figure out PFAs!

If I may add to the bikeshedding, and since PFAs are like others said
"short lambas on steroids", what about borrowing the syntax from them?

Here would be the first-class callable syntax:

fn(...) => $callable(...)

and for PFAs:

fn(...) => $callable(?, 42, ...)

Nicolas


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread David Gebler
On Thu, May 20, 2021 at 8:38 PM Larry Garfield 
wrote:

>
> There's been a lot of rapid iteration, experimentation, and rejection.
> The most recent alternatives are this one from Levi:
>
> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd
>
> And this one from me:
>
> https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8
>
>
Intuitively, I think I prefer your algorithm as these are written up.
Levi's allows for named placeholders which I'm sure for some users is a big
draw. But I think what you're proposing is cleaner and will be better
understood. It resolves a lot of the concerns which came up in the PFA
thread, striking a reasonable balance between benefit and simplicity.

Either way suggests compatibility with Nikita's proposal, assuming use of
the spread operator as the implemented syntax. For this RFC in isolation,
though, it does loosely concern me as a user the proposed syntax looks more
like a function call. I won't bog anyone down arguing the syntax, it's a
minor detail for users to get used to in the grand scheme of things and I'd
definitely rather it was possible to build the more powerful PFA on top
than bin that off, or end up with a convoluted PHP providing competing ways
of doing the same thing.


> * Named arguments make things more complicated.  One of the questions is
> whether named placeholders should be supported or not.  And if they are,
> does that mean you can effectively reorder the arguments in the partial
> application, and what does that mean for usability.  It gets complicated
> and scope-creepy fast.
>

I do share the concern about named arguments and it's one of the reasons I
prefer your proposal. I think scaling back the scope a little bit is
exactly what's needed right now.


> While I agree Nikita's RFC here would be an improvement over 8.0, I don't
> think throwing in the towel on PFA yet is a good idea.  It's a much more
> robust and powerful approach that still gets us the "first class callable"
> syntax we all want (at least I assume we all do), and lots of additional
> power to boot.  I'd rather see us try to drive PFA home to completion.  If
> that proves impossible by early July, then this RFC would still get us
> something this cycle, as long as the syntax is still compatible with PFA.
>

I think this is very sensible, I can only really say I'd rather have
Nikita's proposal land in 8.1 and PFAs in 9.0 done right than have PFAs in
8.1 but in a way which is confusing, ambiguous or problematic for users, or
not covering reasonable expected use cases.


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Rowan Tommins

On 20/05/2021 21:54, Kamil Tekiela wrote:

This would be less confusing than the (...) syntax IMHO. Of course this
still has the same ambiguity as Rowan points out. Is ::$objA->methA a
property or a method? We could solve this problem by specifying the syntax
to always refer to methods/functions. Parentheses could be used to enforce
access to property, e.g. ::($objA->methA) would evaluate the value stored
in the public property of the object $objA



This is precisely the kind of "solution" that I referred to as easy for 
the parser but confusing for humans.


::$objA->methA // method
(::$objA->methA) // method
::($objA->methA) // property
::($objA)->methA // method?
(::$objA)->methA // attempt to access a property of a Closure object?

It's just a mess, IMHO


Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Kamil Tekiela
Hi Nikita,

I would like to just express my feelings. It's a definite YES from me for
first-class callables. We need something to replace [$this,
'privateMethod'].
I just don't like the proposed syntax. The triple period '...' has a
meaning already and reusing the same syntax isn't nice.
I haven't followed the PFA RFC closely, but I don't like that proposal as
it seems to add additional complexity to PHP's syntax for little gain. I
feel like it's just arrow function on steroids.
I know we can already do something like this:

function do_stuff($e) { return $e**2; }
$result = array_map(do_stuff::class, [1,2,3,4]);

I wouldn't mind having a dedicated operator for creating closures in the
same way. e.g.
$result = array_map(do_stuff::closure, [1,2,3,4]);

I understand that ::class creates a string literal and ::closure creates
closure, but from the usability point of view, they would be used in
similar ways.

Many languages have shared symbol tables for constants, functions and
variables. PHP doesn't, so we can't just use the name, but I agree with
Rowan that just using a function's name would be ambiguous even if the
parser allowed for that. We could introduce new syntax for this. I think
Kotlin uses double semicolon in front of the identifier. e.g.
$result = array_map(::do_stuff, [1,2,3,4]);
This would be less confusing than the (...) syntax IMHO. Of course this
still has the same ambiguity as Rowan points out. Is ::$objA->methA a
property or a method? We could solve this problem by specifying the syntax
to always refer to methods/functions. Parentheses could be used to enforce
access to property, e.g. ::($objA->methA) would evaluate the value stored
in the public property of the object $objA

If we land on using the syntax as your RFC proposes then I would ask
Internals to avoid (...) and instead use another symbol inside the
parentheses. I believe any other symbol would look better than triple
period, e.g.  $objA->methA(*)

Kind Regards,
Kamil


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Rowan Tommins

On 20/05/2021 19:16, Alexandru Pătrănescu wrote:

Also, considering the resolution between property and method (or between
constants and static methods) , it's clear that we need a syntax that looks
like the usual invocation:(...), or (?), (...?), ($), ($$), (...$) etc.



I'd like to expand on this point, because I'm seeing a lot of 
suggestions for syntaxes that overlook it.


The following are all valid, but refer to _different_ things called "foo":

foo // a constant called foo
foo() // a function called foo
$foo // a variable called foo

$bar->foo // a property called foo
$bar->foo() // a method called foo

Bar::foo // a class constant
Bar::foo() // a static method
Bar::$foo // a static property

The thing that consistently distinguishes function and method calls is 
the parentheses after them. This holds even for "exotic" combinations:


$foo() // a variable called foo, de-referenced as a callable and then 
invoked
($bar->foo)() // a property called foo, de-referenced as a callable and 
then invoked
foo()() // a function called foo, the return value of which is 
de-referenced as a callable and invoked


Any callable syntax (and, if/when we get one, a partial application 
syntax) that doesn't have the parentheses there is going to run into 
annoying edge cases fast. Not necessarily the kind of edge cases that 
are hard for the parser, but definitely the kind that are confusing to 
humans.



Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Larry Garfield
On Thu, May 20, 2021, at 10:55 AM, Guilliam Xavier wrote:
> On Thu, May 20, 2021 at 5:12 PM Nikita Popov  wrote:
> 
> > On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes  wrote:
> >
> > > Hi, I’m confused by the syntax, when I read it, I think to myself “I know
> > > this, this is just a method call… oh wait, it’s actually a callable”. It
> > > really makes my head hurt.
> > >
> >
> > Yes, I can see how that could be confusing. The current syntax is chosen to
> > be a subset of the partial function application proposal. However, I would
> > also be happy with some other syntax that makes it clearer that this is
> > acquiring a callable and not performing a call.
> >
> 
> Hi, several other syntaxes have been proposed to consideration in the PFA
> thread, and I wouldn't want to start new bikeshedding here; is there a
> place that would be more appropriate to gather the possibilities (like a
> kind of updatable list)?
> 
> Thanks,

There's been a lot of rapid iteration, experimentation, and rejection.  The 
most recent alternatives are this one from Levi:

https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cbfd

And this one from me:

https://gist.github.com/Crell/ead27e7319e41ba98b166aba89fcd7e8

The main takeaways (to give context to Nikita's proposal):

* Because of optional arguments, using the same symbol for "copy one parameter 
from the underlying function" and "copy all remaining parameters from the 
underlying function" is not viable.  It runs into oddball cases where you may 
intend to only use one argument but end up using multiple, especially in array 
operation functions that sometimes silently pass keys along to callbacks if 
they can.  Hence the separate ? and ... that were proposed.

* Named arguments make things more complicated.  One of the questions is 
whether named placeholders should be supported or not.  And if they are, does 
that mean you can effectively reorder the arguments in the partial application, 
and what does that mean for usability.  It gets complicated and scope-creepy 
fast.

* The most important use cases are:
** "prefill nothing, just give me a callable" (which is the case Nikita's RFC 
covers) 
** "reduce an arbitrary function to a single remaining argument", which lets it 
be used by various existing callback functions in the standard library 
(array_map, array_filter, etc.), many user-space APIs, and the pipes RFC that I 
am planning to bring back up once PFA is figured out 
(https://wiki.php.net/rfc/pipe-operator-v2).  

While there are other use cases, the two of those cover the vast majority of 
uses.  (There is some dispute about which of those is larger, or will be larger 
in the future.)

It took a while to realize the first point, which basically killed "? means 
zero or more".  We also went down a rabbit hole of trying to make argument 
reordering work because some people asked for it, but as noted that's a very 
deep rabbit hole.

My gist above was a reduced-scope version of Levi's that uses two symbols and 
drops named placeholders.  It doesn't give us every possible combination, but 
it does give us most reasonable combinations.

Nikita's "just do the first one" RFC (this thread) was proposed at about the 
same time, and takes an even-further scope reduction.

My own take is that the PFA discussion has been overly-bikeshedded, which is 
unfortunate since I think we're quite close to now having a workable answer 
that covers most reasonable use cases.  While I agree Nikita's RFC here would 
be an improvement over 8.0, I don't think throwing in the towel on PFA yet is a 
good idea.  It's a much more robust and powerful approach that still gets us 
the "first class callable" syntax we all want (at least I assume we all do), 
and lots of additional power to boot.  I'd rather see us try to drive PFA home 
to completion.  If that proves impossible by early July, then this RFC would 
still get us something this cycle, as long as the syntax is still compatible 
with PFA.  (Otherwise whenever PFA gets sorted out in the future we end up with 
yet-more-ways to do the same thing that are not optimizations of each other but 
just competing syntax, in which case no one wins.)

--Larry Garfield

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Aleksander Machniak
On 20.05.2021 19:05, Nikita Popov wrote:
>> $fn = ::myFunc;
>>
> Unfortunately, this syntax is trivially ambiguous. "$fn = &$this->myFunc"
> is currently already interpreted as a reference assignment of the property
> $this->myFunc.

could that be just fn(sth)? I mean without the => part.


$fn = fn($this->myFunc);

$fn = fn(myFunc);

$fn = fn(Foo::myFunc);

and then something like this

$partial = fn(Foo::myFunc)[?, 42];

or

$partial = fn(Foo::myFunc, ?, 42);


My earlier idea was that actually cloning a callable could convert it to
a Closure, but I'm not sure now:

$fn = clone $this->myFunc;


or is this a heresy? ;)

-- 
Aleksander Machniak
Kolab Groupware Developer[https://kolab.org]
Roundcube Webmail Developer  [https://roundcube.net]

PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Alexandru Pătrănescu
On Thu, May 20, 2021, 15:48 Nikita Popov  wrote:

> Hi internals,
>
> I'd like to present an RFC for a first-class callable syntax, which is
> intended as a simpler alternative to the partial function application (PFA)
> proposal:
>
> https://wiki.php.net/rfc/first_class_callable_syntax
>
>
This looks good to me. Following some discussions, I understand how this
syntax was proposed. Maybe update also the PFA RFC to be up to date with
the latest info.

Also, considering the resolution between property and method (or between
constants and static methods) , it's clear that we need a syntax that looks
like the usual invocation:(...), or (?), (...?), ($), ($$), (...$) etc.



I have few question related to some behavior.

If we have closure:
$c = function() {};

Will this be true?
$c(...) === $c;
similarly with how it happens for
Closure::fromCallable($c) === $c;
since the RFC makes a lot of comparisons between them.

Also, from performance point of view, do we expect the new syntax to behave
similarly?

And another not practical one:
Will this be valid?
$c(...)(...)(...)(...)();

Regards,
Alex


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Dan Ackroyd
Ondřej Mirtes wrote:
> Hi, I’m confused by the syntax, when I read it,...

That is true of almost any new syntax. Some of us are still getting
used to seeing \ in front of function calls. It doesn't mean that the
syntax choice is a bad one, just that it's something new.

For me, the main questions I ask myself is:

* could I explain what the syntax means to a junior developer?
* would the junior developer be able to remember it?

For both of those questions, the suggested syntax seems fine.

Guilliam Xavier wrote:
> I wouldn't want to start new bikeshedding here; is there a
> place that would be more appropriate to gather the possibilities

Unfortunately I don't think we do have a better place. Being able to
fork conversations so that "not completely off-topic, but not really
that productive and getting in the way of the main discussion stuff",
can be out of the way, but findable, is a feature that would be really
useful for discussions.

Nikita Popov wrote:
> I am generally open to using a different syntax,

Well, you might regret saying that. It might not be appropriate*, but
having $() as marking a closure/callable seems 'clean' to me. Though
obviously novel and likely to cause gut reactions:

$(strlen);
$($foo, bar);
$(Foo, quux);
$($foo->fn);
$($foo);
$($fn);

Each would be equivalent to:

Closure::fromCallable('strlen');
Closure::fromCallable([$foo, 'bar']);
Closure::fromCallable([Foo::class, 'quux']); // aka
Closure::fromCallable('Foo::quux');
Closure::fromCallable($foo->fn);
Closure::fromCallable($foo);
Closure::fromCallable($fn);

For the code:

class Foo {
public $fn;
public function __construct($fn) {
$this->fn = $fn;
}
public function bar() {
}
public static function quux() {
}
public function __invoke() {
}
}

$fn = function() {
echo "I am function\n";
};

$foo = new Foo($fn);

cheers
Dan
Ack

* at least in the sense that it's a big syntax change, for a
relatively small feature.

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Matthew Brown
On Thu, 20 May 2021 at 10:17, Ondřej Mirtes  wrote:

> Hi, I’m confused by the syntax, when I read it, I think to myself “I know
> this, this is just a method call… oh wait, it’s actually a callable”. It
> really makes my head hurt.
>

I agree with the first point — slightly confusing initially, but I can see
myself get used to it. I suggested strlen(=>) as an alternative, not sure
if that would cause parsing difficulties.


> Also, static analysers already have to reason about current code, so
> PHPStan (and Psalm probably too) already supports referencing to callables
> as strings (global functions) and arrays (methods):
>
> $name = 'date';
> $name(1); // Parameter #1 $format of callable 'date' expects string, int
> given.
>

I disagree here: while Psalm can understand what's going on in the above
code, callables are definitely (in my opinion) the most hairy part of PHP's
type system.

The RFC gives an example of something not caught by either PHPStan or Psalm:

https://psalm.dev/r/21217fdfb4
https://phpstan.org/r/6cc8cdc2-ecc6-403d-887d-0f12f4813b75

Discouraging this particular formulation would make affected codebases safe
from this particular error.

Best wishes,

Matt


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Nikita Popov
On Thu, May 20, 2021 at 6:22 PM Luis Henrique 
wrote:

> On 20/05/2021 12:55, Guilliam Xavier wrote:
> > On Thu, May 20, 2021 at 5:12 PM Nikita Popov 
> wrote:
> >
> >> On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes  wrote:
> >>
> >>> Hi, I’m confused by the syntax, when I read it, I think to myself “I
> know
> >>> this, this is just a method call… oh wait, it’s actually a callable”.
> It
> >>> really makes my head hurt.
> >>>
> >>
> >> Yes, I can see how that could be confusing. The current syntax is
> chosen to
> >> be a subset of the partial function application proposal. However, I
> would
> >> also be happy with some other syntax that makes it clearer that this is
> >> acquiring a callable and not performing a call.
> >>
> >
> > Hi, several other syntaxes have been proposed to consideration in the PFA
> > thread, and I wouldn't want to start new bikeshedding here; is there a
> > place that would be more appropriate to gather the possibilities (like a
> > kind of updatable list)?
> >
> > Thanks,
> >
>
> I am much more into advanced features of PFA, but is this case why not
> just use the & operator for "function reference" like C/C++? It is well
> known and solves the ambiguity with method/function call.
>
> $fn = &$this->myFunc;
>
> $fn = 
>
> $fn = ::myFunc;
>

Unfortunately, this syntax is trivially ambiguous. "$fn = &$this->myFunc"
is currently already interpreted as a reference assignment of the property
$this->myFunc.

I have updated
https://wiki.php.net/rfc/first_class_callable_syntax#syntax_choice to
discuss some of the obvious suggestions and why they don't work.

Regards,
Nikita


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Luis Henrique

On 20/05/2021 12:55, Guilliam Xavier wrote:

On Thu, May 20, 2021 at 5:12 PM Nikita Popov  wrote:


On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes  wrote:


Hi, I’m confused by the syntax, when I read it, I think to myself “I know
this, this is just a method call… oh wait, it’s actually a callable”. It
really makes my head hurt.



Yes, I can see how that could be confusing. The current syntax is chosen to
be a subset of the partial function application proposal. However, I would
also be happy with some other syntax that makes it clearer that this is
acquiring a callable and not performing a call.



Hi, several other syntaxes have been proposed to consideration in the PFA
thread, and I wouldn't want to start new bikeshedding here; is there a
place that would be more appropriate to gather the possibilities (like a
kind of updatable list)?

Thanks,



I am much more into advanced features of PFA, but is this case why not 
just use the & operator for "function reference" like C/C++? It is well 
known and solves the ambiguity with method/function call.


$fn = &$this->myFunc;

$fn = 

$fn = ::myFunc;

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Guilliam Xavier
On Thu, May 20, 2021 at 5:12 PM Nikita Popov  wrote:

> On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes  wrote:
>
> > Hi, I’m confused by the syntax, when I read it, I think to myself “I know
> > this, this is just a method call… oh wait, it’s actually a callable”. It
> > really makes my head hurt.
> >
>
> Yes, I can see how that could be confusing. The current syntax is chosen to
> be a subset of the partial function application proposal. However, I would
> also be happy with some other syntax that makes it clearer that this is
> acquiring a callable and not performing a call.
>

Hi, several other syntaxes have been proposed to consideration in the PFA
thread, and I wouldn't want to start new bikeshedding here; is there a
place that would be more appropriate to gather the possibilities (like a
kind of updatable list)?

Thanks,

-- 
Guilliam Xavier


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Nikita Popov
On Thu, May 20, 2021 at 4:16 PM Ondřej Mirtes  wrote:

> Hi, I’m confused by the syntax, when I read it, I think to myself “I know
> this, this is just a method call… oh wait, it’s actually a callable”. It
> really makes my head hurt.
>

Yes, I can see how that could be confusing. The current syntax is chosen to
be a subset of the partial function application proposal. However, I would
also be happy with some other syntax that makes it clearer that this is
acquiring a callable and not performing a call.


> Also, static analysers already have to reason about current code, so
> PHPStan (and Psalm probably too) already supports referencing to callables
> as strings (global functions) and arrays (methods):
>
> $name = 'date';
> $name(1); // Parameter #1 $format of callable 'date' expects string, int
> given.
>

This is only possible for static analyzers that implement relatively
sophisticated and non-local analysis. If you see a random ['A', 'b'] in the
code, you cannot know whether this is just an array, or supposed to be a
reference to A::b() without following the data-flow of the value, and
checking whether it is going to be used in a position that requires a
callable, or passed to a callable parameter.

This means that answering a simple question like "find all references to
this method in the code base" also requires solving data-flow and type
inference problems, which is ... not great.

Apart from the static analysis perspective, having a first-class callable
syntax also fixes the current scoping problems that plague callables (which
can be worked around using Closure::fromCallable), and allows the
elimination of the callable type in favor of the Closure type, which has
much more well-defined semantics. (You will note that callable is already
not usable for typed properties.)

I don't think there's any question that we need a first-class callable
syntax ... it's more a question of how exactly it should look like. The PFA
RFC proposed one possibility. This RFC is another, more limited form.

Some people have also suggested that we should "just" allow writing strlen
to reference the strlen function etc, but this is not viable without a
prior unification of all symbol tables (such syntax conflicts with constant
access, class constant access and object property access).

Regards,
Nikita


Re: [PHP-DEV] [RFC] First-class callable syntax

2021-05-20 Thread Ondřej Mirtes
Hi, I’m confused by the syntax, when I read it, I think to myself “I know
this, this is just a method call… oh wait, it’s actually a callable”. It
really makes my head hurt.

Also, static analysers already have to reason about current code, so
PHPStan (and Psalm probably too) already supports referencing to callables
as strings (global functions) and arrays (methods):

$name = 'date';
$name(1); // Parameter #1 $format of callable 'date' expects string, int
given.