[RFC] Partial Function Application, take 2

php.internals

Larry Garfield

5 years ago
Hi folks. After much off-list discussion, iteration, and consideration, we have a new draft of PFA ready for review. The URL is the same: https://wiki.php.net/rfc/partial_function_application It's a bit long because we wanted to be as precise as possible. However, in short: * Partial application creates a closure object you can use like any other. * A ? indicates "exactly one required parameter here" * A ... indicates "zero or more parameters here" * If the pattern in the partial is compatible with the underlying function, everything "just works" * If it's not compatible, you get an error. * Named placeholders are not supported. * Splat (argument unpacking) is not supported. That gives us the 3 most important use cases, plus many others: arbitrary_function(...) works to reference any function safely. (This is what Nikita's mini-scoped proposal did.) some_func(1, 2, ?, 5) works to reduce any function to single-argument, which makes it useful in many callback situations. any_func($all, $params, ...) works to provide all the arguments to a function but not call it yet; you can then cal the resulting closure later with no arguments to actually invoke it. We're reasonably confident that we have all the ins and outs covered, and in a performant way. Because it's such a heavy rework, though, we want to give it enough time for the discussion to settle, so won't call a vote for at least 2 weeks from today (give or take the feedback we get here). Cheers!
-- Larry Garfield larry@garfieldtech.com

Mike Schinkel

5 years ago
> On Jun 2, 2021, at 1:45 PM, Larry Garfield <larry@garfieldtech.com> wrote: > > Hi folks. After much off-list discussion, iteration, and consideration, we have a new draft of PFA ready for review. > > The URL is the same: > > https://wiki.php.net/rfc/partial_function_application
Really excellent work, all!
> It's a bit long because we wanted to be as precise as possible. However, in short: > > * Partial application creates a closure object you can use like any other. > * A ? indicates "exactly one required parameter here" > * A ... indicates "zero or more parameters here"
My only comment/request/suggestion is to consider Mark Randall's suggestion to use `...?` instead, for the reasons he mentioned in his email to the list: https://externals.io/message/114157#114666 <https://externals.io/message/114157#114666> Plus Levi Morrison seemed to approve: https://externals.io/message/114157#114667 <https://externals.io/message/114157#114667> -Mike

Björn Larsson

5 years ago
Den 2021-06-02 kl. 22:16, skrev Mike Schinkel:
>> On Jun 2, 2021, at 1:45 PM, Larry Garfield <larry@garfieldtech.com> wrote: >> >> Hi folks. After much off-list discussion, iteration, and consideration, we have a new draft of PFA ready for review. >> >> The URL is the same: >> >> https://wiki.php.net/rfc/partial_function_application > > Really excellent work, all! > >> It's a bit long because we wanted to be as precise as possible. However, in short: >> >> * Partial application creates a closure object you can use like any other. >> * A ? indicates "exactly one required parameter here" >> * A ... indicates "zero or more parameters here" > > My only comment/request/suggestion is to consider Mark Randall's suggestion to use `...?` instead, for the reasons he mentioned in his email to the list: > > https://externals.io/message/114157#114666 <https://externals.io/message/114157#114666> > > Plus Levi Morrison seemed to approve: > > https://externals.io/message/114157#114667 <https://externals.io/message/114157#114667> > > -Mike >
I second this opinion. So is the "...?" syntax something that will be considered? r//Björn Larsson

Jordi Boggiano

5 years ago
On 07/06/2021 21:50, Björn Larsson wrote:
> Den 2021-06-02 kl. 22:16, skrev Mike Schinkel: >> My only comment/request/suggestion is to consider Mark Randall's >> suggestion to use `...?` instead, for the reasons he mentioned in his >> email to the list: >> >> https://externals.io/message/114157#114666 >> <https://externals.io/message/114157#114666> >> >> Plus Levi Morrison seemed to approve: >> >> https://externals.io/message/114157#114667 >> <https://externals.io/message/114157#114667> >> >> -Mike >> > > I second this opinion. So is the "...?" syntax something that will > be considered? >
As this was still not answered.. I would like to just drop a +1. I do find the symmetry of "...?" / "?" quite appealing too, ensuring that you always get a "?" to indicate a partial application. If it's controversial, Mark Randall's idea of having it be a subvote sounds good to me to make sure the debate is closed once and for all. Ignoring it now to get another RFC trying to change the syntax in two months isn't helpful :) Aside from that, also +1 on "good work everyone involved", this looks pretty solid now and I'm looking forward to the addition! Best, Jordi
-- Jordi Boggiano @seldaek - https://seld.be

Guilliam Xavier

5 years ago
On Wed, Jun 2, 2021 at 7:47 PM Larry Garfield <larry@garfieldtech.com> wrote:
> Hi folks. After much off-list discussion, iteration, and consideration, > we have a new draft of PFA ready for review. > > The URL is the same: > > https://wiki.php.net/rfc/partial_function_application >
Hi, thanks all for the reworks! I just thought to something: does it support nullsafe calls, e.g. `$foo?->bar(?)`? and if yes, what is the signature of the Closure when `$foo === null` (and does it make a difference if, inside a function, it was created as a local variable `$foo = null;` vs received as a typed parameter `?Foo $foo`)? Related, for `$null === null`, is `$c = $null->bar(?);` / `$c = $null::baz(?);` an immediate error, or only later when calling `$c($arg)`? Regards,
-- Guilliam Xavier

Larry Garfield

5 years ago
On Thu, Jun 10, 2021, at 3:17 AM, Guilliam Xavier wrote:
> On Wed, Jun 2, 2021 at 7:47 PM Larry Garfield <larry@garfieldtech.com> > wrote: > > > Hi folks. After much off-list discussion, iteration, and consideration, > > we have a new draft of PFA ready for review. > > > > The URL is the same: > > > > https://wiki.php.net/rfc/partial_function_application > > > > Hi, thanks all for the reworks! I just thought to something: does it > support nullsafe calls, e.g. `$foo?->bar(?)`? and if yes, what is the > signature of the Closure when `$foo === null` (and does it make a > difference if, inside a function, it was created as a local variable `$foo > = null;` vs received as a typed parameter `?Foo $foo`)?
I just checked, and it... sort of supports nullsafe. Rather, if you try to partial a method on a null object, you get null back for your closure. Then when you try to call it, you get a "cannot invoke null" error. Which... I think makes sense. cf: https://3v4l.org/4XeB3/rfc#focus=rfc.partials As a cute side effect, Joe pointed out you could do this: https://3v4l.org/ERRdY/rfc#focus=rfc.partials I wouldn't really call that a feature, but more of a side effect of the implementation. Please don't count on that behavior. I also discovered while checking that nullsafe differentiates between null and undefined. That was unexpected, but not related to the topic at hand. :-)
> Related, for `$null === null`, is `$c = $null->bar(?);` / `$c = > $null::baz(?);` an immediate error, or only later when calling `$c($arg)`?
That dies with "call to member function on null" when trying to create the partial: https://3v4l.org/E6MgK/rfc#focus=rfc.partials --Larry Garfield

Guilliam Xavier

5 years ago
On Thu, Jun 10, 2021 at 4:34 PM Larry Garfield <larry@garfieldtech.com> wrote:
> On Thu, Jun 10, 2021, at 3:17 AM, Guilliam Xavier wrote: > > On Wed, Jun 2, 2021 at 7:47 PM Larry Garfield <larry@garfieldtech.com> > > wrote: > > > > > https://wiki.php.net/rfc/partial_function_application > > > > for `$null === null`, is `$c = $null->bar(?);` / `$c = > > $null::baz(?);` an immediate error, or only later when calling > `$c($arg)`? > > That dies with "call to member function on null" when trying to create the > partial: > > https://3v4l.org/E6MgK/rfc#focus=rfc.partials >
That makes sense (eager evaluation of non-placeholder "arguments", including the called-on object).
> > does it > > support nullsafe calls, e.g. `$foo?->bar(?)`? and if yes, what is the > > signature of the Closure when `$foo === null`? > > I just checked, and it... sort of supports nullsafe. Rather, if you try > to partial a method on a null object, you get null back for your closure. > Then when you try to call it, you get a "cannot invoke null" error. > Which... I think makes sense. > > cf: https://3v4l.org/4XeB3/rfc#focus=rfc.partials
Well I find that unexpected :/
> As a cute side effect, Joe pointed out you could do this: > > https://3v4l.org/ERRdY/rfc#focus=rfc.partials
So there's a "workaround", although I wouldn't call it precisely "cute"...
> I wouldn't really call that a feature, but more of a side effect of the > implementation. Please don't count on that behavior. >
I'd rather not indeed ;) Since `$null?->whatever(1, 'a')` currently always returns null without error, shouldn't `$null?->whatever(?, 'a')` return a closure (with a signature built from the placeholders only) that will return null when called (i.e. equivalent to `fn (mixed $arg1) => null` here)? Thanks,
-- Guilliam Xavier

Dan Ackroyd

5 years ago
On Thu, 10 Jun 2021 at 18:32, Guilliam Xavier <guilliam.xavier@gmail.com> wrote:
> Since `$null?->whatever(1, 'a')` currently always > returns null without error, shouldn't `$null?->whatever(?, 'a')` return a > closure (with a signature built from the placeholders only) that will > return null when called (i.e. equivalent to `fn (mixed $arg1) => null` > here)?
No. The short circuiting should happen in the same place, no matter what is to the right of the "?->". Having the behaviour vary and sometimes not return null, would be highly surprising. cheers Dan Ack

Guilliam Xavier

5 years ago
On Thu, Jun 10, 2021 at 7:32 PM Guilliam Xavier <guilliam.xavier@gmail.com> wrote:
> > Since `$null?->whatever(1, 'a')` currently always returns null without > error, shouldn't `$null?->whatever(?, 'a')` return a closure (with a > signature built from the placeholders only) that will return null when > called (i.e. equivalent to `fn (mixed $arg1) => null` here)? >
Ah, we can also see `$foo?->bar(?)` as simply "desugaring" to `$foo === null ? null : $foo->bar(?)`, so the current behavior makes sense too (and maybe even "more")... I guess I was confused to get a "null-implying error" despite using a "null-safe" call syntax :s (There's also the possibility of not supporting it, but I guess that would be a lose-lose...)
-- Guilliam Xavier

Guilliam Xavier

5 years ago
Sorry, me again :s I have tested the examples from https://wiki.php.net/rfc/partial_function_application on https://3v4l.org/#focus=rfc.partials and several of them currently give an error: - Ex 10: on the line `$c = stuff(?, ?, f: 3.5, ..., p: $point);` => Fatal error: Named arguments must come after all place holders (typo I guess, `$c = stuff(?, ?, ..., f: 3.5, p: $point);` is OK) - (Ex 11: no error but a typo: `'hi'` vs `'foo'`) - Ex 16: for the last call `(four(..., d: 4, a: 1))(2, 3);` => Fatal error: Uncaught ArgumentCountError: four(): Argument #2 ($b) not passed (on the function definition line) (`(four(..., d: 4, a: 1))(2, 3, 5, 6);` idem, but `(four(..., d: 4, a: 1))(b: 2, c: 3);` throws an "Unknown named parameter $b" Error on the call line) (weird) - func_get_args() and friends: one the last line `$f(1, 2);` (after `$f = f(?);`) => Fatal error: Uncaught Error: too many arguments for application of f, 2 given and a maximum of 1 expected (can make sense, e.g. https://externals.io/message/114532#114554 ) - (Callable reference: no error but a typo: `$f` vs `$foo`) - Optimizations: on the line `$boo = $baz(4, ...);` => Fatal error: Uncaught Error: too many arguments and or place holders for application of Closure::__invoke, 1 given and a maximum of 0 expected (`$boo = $baz(?);` throws the same error, but `$boo = $baz(4);` throws a "not enough arguments for implementation of foo, 4 given and exactly 5 expected" Error, and `$boo = $baz(...);` makes the subsequent `$boo(5);` throw a "not enough arguments ..." Error) (weird, looks like `$bar = $foo(2, ...);` and/or `$baz = $bar(3, ...);` dropped too many params) Regards,
-- Guilliam Xavier

Joe Watkins

5 years ago
There's a couple of typos in the RFC, which Larry will fix when he has time. There was also a typo in patch, and a fault in patch. All fixed. pending tests, 3v4l won't update until tomorrow. Cheers Joe On Fri, 11 Jun 2021 at 13:02, Guilliam Xavier <guilliam.xavier@gmail.com> wrote: