Re: First-class callable partial application
| From: | Robert Landers | Date: | Wed, 15 Mar 2023 10:17:04 +0000 |
| Subject: | Re: First-class callable partial application | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 12 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-119707@lists.php.net to get a copy of this message | ||
On Tue, Mar 14, 2023 at 5:58 PM Larry Garfield <larry@garfieldtech.com> wrote:
>
> 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
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
Hey Larry,
> 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.
This is why my approach was one of syntax sugar. Sure, it would make
the call stack weird during exceptions, but all-in-all, not much
changes from an engine standpoint. Most of the changes were to the
grammar IIRC. I'll hop on my old computer this weekend and submit a PR
to make the discussion easier.