Le ven. 21 mai 2021 à 16:31, Larry Garfield <la...@garfieldtech.com> 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 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 implementation detail.
>

And the point of PFA is also to copy the existing signature, which is a
significant difference with short closures.
This completely disqualifies my proposal :)
But this also highlights a critical reason for adding PFAs: they're not
only syntax sugar to write short closure, but an abstraction over the
signature of partialized callables!

Last proposal, just to be sure we screened them all: using "...?" instead
of "..."
$callable(...?)




> > >> 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.
>
> That is precisely the conclusion I reached and what my writeup says: The
> only placeholders are positional placeholders.  Named arguments are fine,
> but not named placeholders.
>
> > > 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
>
> As above, not really viable.
>
>
> Also, to answer Andreas as long as I'm here: Supporting "new Foo" with PFA
> is a separate question.  As noted in the currently written draft of the
> RFC, the problem is that object creation is not a function call; the object
> is created, then the __construct initializer is called.  A naive PFA
> implementation would therefore create the object once, couple it to the
> partial, and then calling the partial repeatedly would return the same
> object, rather than repeatedly making a new object.  Joe already figured
> out how to special case that, though, so it's a non-issue.
>
> Both Levi's writeup and mine could support PFA constructors, AFAIK.
>
> --Larry Garfield
>

Nicolas

Reply via email to