Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:114554
Return-Path: <larry@garfieldtech.com>
Delivered-To: mailing list internals@lists.php.net
Received: (qmail 55002 invoked from network); 21 May 2021 14:20:34 -0000
Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5)
  by pb1.pair.com with SMTP; 21 May 2021 14:20:34 -0000
Received: from php-smtp4.php.net (localhost [127.0.0.1])
	by php-smtp4.php.net (Postfix) with ESMTP id 100BA1804D8
	for <internals@lists.php.net>; Fri, 21 May 2021 07:30:51 -0700 (PDT)
X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net
X-Spam-Level: 
X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED,
	DKIM_VALID,RCVD_IN_DNSWL_LOW,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,
	SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2
X-Spam-Virus: No
X-Envelope-From: <larry@garfieldtech.com>
Received: from wout2-smtp.messagingengine.com (wout2-smtp.messagingengine.com [64.147.123.25])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256)
	(No client certificate requested)
	by php-smtp4.php.net (Postfix) with ESMTPS
	for <internals@lists.php.net>; Fri, 21 May 2021 07:30:50 -0700 (PDT)
Received: from compute3.internal (compute3.nyi.internal [10.202.2.43])
	by mailout.west.internal (Postfix) with ESMTP id C83181529
	for <internals@lists.php.net>; Fri, 21 May 2021 10:30:48 -0400 (EDT)
Received: from imap8 ([10.202.2.58])
  by compute3.internal (MEProxy); Fri, 21 May 2021 10:30:48 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=
	messagingengine.com; h=content-transfer-encoding:content-type
	:date:from:in-reply-to:message-id:mime-version:references
	:subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender
	:x-sasl-enc; s=fm2; bh=tcYeFqTl/P4BmELAvJ3lZOnfDnrZqeNOma8nCkdvr
	B0=; b=qpd0g+ewsidbeWIgYqCHoj2ft3oj+Svj572A81/ezncEL9lpTVU/ISmPU
	ho2gh+iyJUubrfVPB7+r77OsOLyo+BZaAxKCG5E1+RGiUAbjKa0K0RJJutOoLGTo
	Mdm6WjajmOfBLXDdxPTG/GTb3G4UiptZCReQmJJDWUt3NedpFe8sCIgSdQwLGCPm
	SSknOjHnau1FINib70xMPNUkr4SDTC4D0ZVoBmia/YL0w0G56iupiGCt0L4zYw31
	r+ycQPzDLtHLJ/IUx7kZwoPkpbBZa4L6TI335vUJMhbuHGf3uBXJ2BlD/UoaiB7o
	aHeW22RqjIwM4bKkjjnyDl9RqThLg==
X-ME-Sender: <xms:GMSnYNP39nwZGo9UuCm1i2I0g6vvJYi2v65LKKP0GtL7tsJgD9brfQ>
    <xme:GMSnYP8ySdAyyDziHU1vDUoHa0rJaO2KO-jOoYyRsdmehPMz_GpVBR09wnQQc7Fow
    WDiyYAIm0MrRQ>
X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrvdejfedgjeekucetufdoteggodetrfdotf
    fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen
    uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne
    cujfgurhepofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgr
    rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg
    homheqnecuggftrfgrthhtvghrnhephfektdffgffhkeeiudehvdehfefgfeehuefgvdel
    teetkeetgfetjeeiledtleeknecuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlh
    hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehg
    rghrfhhivghlughtvggthhdrtghomh
X-ME-Proxy: <xmx:GMSnYMQocI9CM4_-2k6Jaic4PIbylb3ng-HfUwkPU7qhmX-VRxynYg>
    <xmx:GMSnYJvf9KjTMIRwn-cVTl-Zmo2jVEqByHR1D3JySPllKMJUJQa21Q>
    <xmx:GMSnYFc7ULqP6alwMyqPoj88JS6seNWcfP0OpfsHErst5rr6S0TYmw>
    <xmx:GMSnYA8JDp6U_dPkWH7o_44SuznnXXGC77xsPBq37p5XmoJeUDFwmg>
Received: by mailuser.nyi.internal (Postfix, from userid 501)
	id 2F12B3A03D0; Fri, 21 May 2021 10:30:48 -0400 (EDT)
X-Mailer: MessagingEngine.com Webmail Interface
User-Agent: Cyrus-JMAP/3.5.0-alpha0-448-gae190416c7-fm-20210505.004-gae190416
Mime-Version: 1.0
Message-ID: <13cb59de-f335-4532-9e7a-400499661dbf@www.fastmail.com>
In-Reply-To: 
 <CAOWwgpmQeN9J9pTOenTrSngzWAN_P6XRf4Z1CNrSmDFGHjtsRg@mail.gmail.com>
References: 
 <CAF+90c_iYjsDWoqPaDtavVgj2WFdpiuBmGeQZFAqokVoVZTxoA@mail.gmail.com>
 <CALfTnfXDTvrtA9-hN+UH+qs3iS9q34jseunBD7YumGkonrSwXA@mail.gmail.com>
 <CAF+90c9DpTWzqu9S9=CkuaW=RnbneXUbRbqhuJDRBPwUz9RMsA@mail.gmail.com>
 <CAC5V6ghco1H4jT2Y_ug3LTWfyAz_5f6iCObGrdDfXn2PeuXgLg@mail.gmail.com>
 <fa269b69-9bac-4a81-8c65-409766f1c9f8@www.fastmail.com>
 <CAOWwgp=QZ0jAy4Qc+w7grEEN0b9KCX+Uec12AQoYPQHTqQ-Ddg@mail.gmail.com>
 <CAOWwgpmQeN9J9pTOenTrSngzWAN_P6XRf4Z1CNrSmDFGHjtsRg@mail.gmail.com>
Date: Fri, 21 May 2021 09:30:26 -0500
To: "php internals" <internals@lists.php.net>
Content-Type: text/plain;charset=utf-8
Content-Transfer-Encoding: quoted-printable
Subject: Re: [PHP-DEV] [RFC] First-class callable syntax
From: larry@garfieldtech.com ("Larry Garfield")

On Fri, May 21, 2021, at 2:52 AM, Nicolas Grekas wrote:
> Sorry for self-reply, this needs some clarifications :)
>=20
> Le ven. 21 mai 2021 =C3=A0 09:17, Nicolas Grekas <nicolas.grekas+php@g=
mail.com>
> a =C3=A9crit :


> >> There's been a lot of rapid iteration, experimentation, and rejecti=
on.
> >> The most recent alternatives are this one from Levi:
> >>
> >> https://gist.github.com/morrisonlevi/f7cf949c02f5b9653048e9c52dd3cb=
fd
> >>
> >> 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 on=
e
> >> parameter from the underlying function" and "copy all remaining par=
ameters
> >> 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 mult=
iple,
> >> especially in array operation functions that sometimes silently pas=
s 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 actu=
ally a
> > critical feature of the engine when writing BC layers by adding extr=
a
> > arguments via this possibility.
> >
>=20
> 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 t=
ime that this issue existed either.)  The classic example, ported from J=
avascript:

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

$array =3D ['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 fu=
nctions like array_walk() will try to use  the optional one if they can.=
.. even if doing so makes no logical sense.  Having ? capture all argume=
nts 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 ... sy=
mbol for when you really do mean "and all the rest".

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

I think the plan would be that extra passed arguments to a partialed fun=
ction would still forward through, but that may end up being more diffic=
ult than expected. =20

> In the 2nd gist, I read "If the current position is a ..., copy all
> > remaining parameters from the underlying function, including a varia=
dic."
> > But to me it's important that all extra arguments are forwarded to t=
he
> > 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 alon=
g extraneous arguments is a bug, not a feature.  I don't have a strong f=
eeling about it, but some do.)

> > * Named arguments make things more complicated.  One of the question=
s is
> >> whether named placeholders should be supported or not.  And if they=
 are,
> >> does that mean you can effectively reorder the arguments in the par=
tial
> >> application, and what does that mean for usability.  It gets compli=
cated
> >> and scope-creepy fast.
> >>
> >
> > For the userland pov, the principle of least surprise would say we s=
hould
> > answer yes to both questions.
>=20
> Reading your gists, I'm with drawing this expectation.
>=20
> 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:?)
>=20
> 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 b=
e
> allowed IMHO. Aka this should be interpreted only as a partial call.
>=20
> *If* we need a way to reorder arguments, I think it would be natural a=
lso
> to be able to *rename* arguments.

Which is also where the rabbit hole gets extra deep, and why I am perfec=
tly happy to just disallow named placeholders.  In the rare use cases wh=
ere you really do want/need to reorder arguments and do other esoteric t=
hings, 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 maki=
ng the most common cases nicer.

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

At that point we're not getting any benefit over just using arrow functi=
ons.  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-cl=
osure object is an implementation detail.

> >> We also went down a rabbit hole of trying to make argument reorderi=
ng
> >> work because some people asked for it, but as noted that's a very d=
eep
> >> 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 pars=
e 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 fin=
e, 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 work=
able
> >> 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 th=
e towel
> >> on PFA yet is a good idea.  It's a much more robust and powerful ap=
proach
> >> that still gets us the "first class callable" syntax we all want (a=
t least
> >> I assume we all do), and lots of additional power to boot.  I'd rat=
her 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 lon=
g 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 w=
hich
> >> case no one wins.)
> >>
> >
> > I agree. Let's figure out PFAs!
> >
> > If I may add to the bikeshedding, and since PFAs are like others sai=
d
> > "short lambas on steroids", what about borrowing the syntax from the=
m?
> >
> > Here would be the first-class callable syntax:
> >
> > fn(...) =3D> $callable(...)
> >
> > and for PFAs:
> >
> > fn(...) =3D> $callable(?, 42, ...)
> >
> > Nicolas

As above, not really viable.


Also, to answer Andreas as long as I'm here: Supporting "new Foo" with P=
FA is a separate question.  As noted in the currently written draft of t=
he 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 sa=
me object, rather than repeatedly making a new object.  Joe already figu=
red out how to special case that, though, so it's a non-issue.

Both Levi's writeup and mine could support PFA constructors, AFAIK. =20

--Larry Garfield