Re: First-class callable partial application
| From: | Larry Garfield | Date: | Tue, 14 Mar 2023 16:57:57 +0000 |
| Subject: | Re: First-class callable partial application | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-119694@lists.php.net to get a copy of this message | ||
On Tue, Mar 14, 2023, at 8:50 AM, Robert Landers wrote:
> On Tue, Mar 14, 2023 at 1:57 PM Rowan Tommins <rowan.collins@gmail.com> wrote:
>>
>> On Tue, 14 Mar 2023 at 10:39, Bob Weinand <bobwei9@hotmail.com> wrote:
>>
>> > Hey Rowan,
>> >
>> > do we actually need *positional* partial application, after a ... token?
>> >
>> > Would it not be enough, to simply forbid positional arguments after a ...
>> > and just allow named arguments? These already have well defined position
>> > independent semantics.
>> >
>> > There may be some desire for a single argument placeholder later on, but
>> > this can be introduced later, separately.
>> >
>>
>>
>> Yes, named parameters would certainly be better than left-to-right only.
>> It's definitely less elegant, though, and given that PFA is largely
>> short-hand for a short closure anyway, I think conciseness is quite an
>> important aim.
>>
>> To take a couple of the above examples, and compare existing short closure,
>> fully positional PFA, and named-after-placeholder PFA:
>>
>> $isLogger = fn($object) => is_subclass_of($object, LoggerInterface::class,
>> false);
>> $isLogger = is_subclass_of(?, LoggerInterface::class, false);
>> $isLogger = is_subclass_of(..., class: LoggerInterface::class,
>> allow_string: false);
>>
>> $priceFormatter = fn(float $num) => number_format($num, 2, ',',
>> '..');
>> $priceFormatter = number_format(?, 2, ',', '.');
>> $priceFormatter = number_format(..., decimals: 2, decimal_separator: ',',
>> thousands_separator: '.');
>>
>> Arguably the named param version is more explicit, but in some cases it's
>> significantly longer than manually defining a closure, whereas fully
>> positional PFA is always shorter.
>>
>> Regards,
>> --
>> Rowan Tommins
>> [IMSoP]
>
> Something I was partial to (pun slightly intended), when thinking
> about it last summer was to put named parameters with dots following,
> like this:
>
> $isLogger = is_subclass_of(object_or_class..., LoggerInterface::class, false);
> // or, since this is a beginning/end partial, this is the same:
> $isLogger = is_subclass_of(..., LoggerInterface::class, false);
>
> $isLogger(object_or_class: $myClass);
> // or
> $isLogger($myClass);
>
> $priceFormatter = number_format(num..., 2, ',', '.');
>
> At least, that was what I was going to propose, according to my notes.
> Looking at it 8 months later, I still kinda like it.
For reference, in the original RFC we had the following rules:
```
This RFC introduces two place holder symbols:
The argument place holder ? means that exactly one argument is expected at this position.
The variadic place holder ... means that zero or more arguments may be supplied at this
position.
The following rules apply to partial application:
... may only occur zero or one time
... may only be followed by named arguments
named arguments must come after all place holders
named placeholders are not supported
```
The reason for that was, I believe, because it was too complicated figure out the signature of the
resulting closure if named placeholders were allowed after the
... . Optional
arguments also got weird, IIRC. We went around *a lot* on the details here before settling on the
syntax we did.
I agree that requiring all partials to used named args would be a big step down for usability.
But again, none of this addresses the root issue that doomed the previous RFC: Any syntax that
involves a runtime determination of "is this a function call or a partial application?" is
going to involve some really tricky dancing along the critical path of all function calls. Even
though Joe's implementation had no significant performance impact (AFAIR), it still made the
code more complex and potentially harder to optimize in the future.
So the only ways forward would be:
1) Find another approach in the implementation that doesn't have that problem, which may then
changes to the proposed syntax and possibility capabilities. (I had suggested some prefix on the
call to indicate that it's a partial and not a call, like %foo(1, ?, 3, ...) or something.)
2) The voter base shifts and/or changes its mind and decides that the extra complexity is worth it.
Redoing the syntax bikeshedding from 3 years ago (dear god, it's been 3 years?) before one of
those two is answered is not productive. New engine approach first, then syntax based on what that
approach allows.
--Larry Garfield