Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:114554 Return-Path: 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 ; 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: 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 ; 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 ; 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: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduledrvdejfedgjeekucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgr rhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtg homheqnecuggftrfgrthhtvghrnhephfektdffgffhkeeiudehvdehfefgfeehuefgvdel teetkeetgfetjeeiledtleeknecuffhomhgrihhnpehgihhthhhusgdrtghomhenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehg rghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: 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: References: Date: Fri, 21 May 2021 09:30:26 -0500 To: "php internals" 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 > 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