Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118924 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 36931 invoked from network); 31 Oct 2022 15:08:18 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 31 Oct 2022 15:08:18 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id C7DF01804F8 for ; Mon, 31 Oct 2022 08:08:17 -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.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_NONE, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS19151 66.111.4.0/24 X-Spam-Virus: No X-Envelope-From: Received: from out4-smtp.messagingengine.com (out4-smtp.messagingengine.com [66.111.4.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 31 Oct 2022 08:08:17 -0700 (PDT) Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) by mailout.nyi.internal (Postfix) with ESMTP id 6F77A5C017E for ; Mon, 31 Oct 2022 11:08:16 -0400 (EDT) Received: from imap50 ([10.202.2.100]) by compute1.internal (MEProxy); Mon, 31 Oct 2022 11:08:16 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= garfieldtech.com; h=cc:content-transfer-encoding:content-type :date:date:from:from:in-reply-to:in-reply-to:message-id :mime-version:references:reply-to:sender:subject:subject:to:to; s=fm3; t=1667228896; x=1667315296; bh=sUSGa5Og6Et960XpTUVv+WIiU UI0fgZ3Fc834wwJj2I=; b=fRQwbAMNJ9ZM1wOiRBEx6ajGUoKytaiinmrQDpDKj g51+mawIiTHsh6zS3V51bOx5nUq9aMAcA/vGDDR3g4bnLzJRw5cXPbcpBWGsaK7k V7Ep2KYwXNV8mpvT4zyRiVfPf33ozqcaAXftxm2dzSudpZ3oIzsyg2vnw0UVjdNi x2WRdc0mnEJkNk5nXv6EmogM/s8WCwCWb2lOdRchF/7W2XMrQQFZZrIG2UfnGHpj behIRjVhRd1cdFV8Uj2otErwnJNy3Z+p1/llYvPwJj1KiYnXI6tcE3g2V7BQPBRQ x5ZoCVDznrPpjUb2lruwJ7XX9biZiYrUX9fhYpLdcA4qA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:content-type :date:date:feedback-id:feedback-id:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:sender :subject:subject:to:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm3; t=1667228896; x=1667315296; bh=s USGa5Og6Et960XpTUVv+WIiUUI0fgZ3Fc834wwJj2I=; b=mZyOg+dO51Nn+CKrt GZ0yxgxoBY6Dzre8Va2QJkFYnmSYliZ8Y60+xzDyqs6Nl5+rsksetpHdeFLo/0oR vcE/u7MDybzGWnFUmLmbm2RXs2k+Udy9sKDOF9zMkjudTX2q0Oto34Kp+bnnLPtl 5XjRG0dFpFy67mxe5P/PBWa40fIY/AeR4eNuui3DIkEjqgkWHO2NQ2Fi40NrngXa mU4VSlaRcs1fJzJMSW0cQjDBB80b1fmWHwWI3zq3sgzBCMzUtMbyRdSp2aLCNg6u +W41SNZ/WOb/EgitJvAqbGbc8nVu4fsNE5u3CVG/lMlM0WLJtb2NT4tfOenMYLRx IV//g== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvgedrudefgdejvdcutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefofgggkfgjfhffhffvufgtgfesthhqredtreerjeenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucggtffrrghtthgvrhhnpeffffffjeffudfggeevvdeitdetvdfgjefffeffjeel feejteevheeghffhvdfgleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmh grihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Feedback-ID: i8414410d:Fastmail Received: by mailuser.nyi.internal (Postfix, from userid 501) id 2F33E1700089; Mon, 31 Oct 2022 11:08:16 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.7.0-alpha0-1087-g968661d8e1-fm-20221021.001-g968661d8 Mime-Version: 1.0 Message-ID: <04e1fa49-71d7-4999-aea2-d4d3133dabd6@app.fastmail.com> In-Reply-To: <0226a847-2a07-8909-68a9-a802756db108@bastelstu.be> References: <960d38a8-c2ad-4cd3-9041-ce42aa38bd18@app.fastmail.com> <0226a847-2a07-8909-68a9-a802756db108@bastelstu.be> Date: Mon, 31 Oct 2022 10:07:55 -0500 To: "php internals" Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] Proposal: Expanded iterable helper functions and aliasing iterator_to_array in `iterable\` namespace From: larry@garfieldtech.com ("Larry Garfield") On Sun, Oct 30, 2022, at 3:25 PM, Tim D=C3=BCsterhus wrote: > Hi > > On 10/30/22 17:22, Larry Garfield wrote: >> 2. There are ample use cases for most operations to return an array o= r a lazy iterable. Both totally exist. I solved that by also having a = separate version of each function, eg, amap() vs itmap(). The former re= turned an array, the latter returned a generator that generated the equi= valent array. It would be a fatal design flaw to not account for this. = Yes, this balloons the number of such functions, which sucks, but that'= s PHP for you. > > Please not. Only provide functions that return an iterable without=20 > giving any further guarantees, because =E2=80=A6 > >> A possible alternative would be to always return a lazy iterable in a= ll circumstances and assume someone can use to_array() or equivalent on = the result if they want it as an array. (That's effectively what Python= 3 does with comprehensions.) However, that could have non-trivial perf= ormance impact since generators are slower than plain arrays. > > =E2=80=A6 this works. The users should not need to think about what re= turn type=20 > is more useful for their specific use case. > > The heavy lifting / optimization should be left to the compiler /=20 > engine, similarly how a fully qualified 'is_null()' is also optimized,=20 > such that no actual function call happens [1]. > > Even if this kind of optimization does not happen in the first version= ,=20 > this should not be a reason to clutter the API surface. I'm open to this approach, but we should be mindful of the ergonomics. = Specifically, I don't think to_array() as an answer is workable unless w= e have some built-in chaining mechanism, pipes or similar. Otherwise, y= ou're effectively requiring anyone who wants to ensure they have an arra= y (which will be a lot of people) to write to_array(some_stuff_here()); All the time, which is considerably less ergonomic than=20 some_stuff_here() |> to_array(); Especially if there's more than one operation involved. =20 Side note: Should there instead be to_list() (which implies dropping key= s and reindexing) and to_assoc() (which implies keeping keys and merging= on key if appropriate)? That seems much more self-documenting than to_= array(true) or whatever. >> 3. Feel free to borrow liberally, design-wise, from the above code. = There's a few more methods in there that could be of use, too. Note, th= ough, that all are designed to be used with a pipe(), so they mostly ret= urn a closure that has been manually partially applied with everything e= xcept the iterable, so you get a single-argument function, which is what= a pipe() or compose() chain needs. >>=20 >> Third, speaking of pipe, I disagree with Tim that putting the callbac= k first would be easier for pipe/partials. If we ever get partials simi= lar to previously implemented, then the argument order won't matter. If= we get pipes as I've previously proposed, then none of these functions = are directly usable because they're multi-argument. >>=20 >> The alternative I've considered is somewhat inspired by Elixir (assum= ing I understand the little Elixir I've read), in which a function after= a |> is automatically assumed to be partially applying everything but t= he first argument. So $list |> map($callable) translates to map($list, = $callable). I've not decided yet if that's a good way to avoid needing = full partial application or a good way to make horribly confusing code. = But if that were to happen, it would only work if all of these function= s took the iterable, the "object to be operated on", as their first argu= ment. >>=20 > > With Haskell, from which my functional programming experience comes,=20 > it's the exact inverse: All functions are automatically partially=20 > applied [2], thus in a pipe the "missing" parameter comes last, not=20 > first as with Elixir. > > So I guess there is no right or wrong and it depends on the programmin= g=20 > language which variant feels more natural. I still prefer having the=20 > callback first for the reasons I've outlined, but in the end I'm happy=20 > as long as it's consistent. Mm, yes, the root question is what kind of auto-partialing we are going = to have. Right now we have none, which is problematic for any sort of c= omposition, which these iterable functions are going to want to have. W= hether we partial from the left or from the right will determine how we = order parameters for functions we expect to be partialed. =20 We should bear in mind that PHP has a couple of features that complicate= matters; namely optional arguments, variadics, and named arguments. Th= e previous RFC that Joe wrote handled all of those as gracefully as I th= ink is possible, but the complexity was apparently too high for too many= folks. He didn't seem confident that a less-complex approach was possi= ble, though. I know this is veering off topic, but one idea I had kicked around that = Joe didn't like was a function call prefix to indicate that it was a par= tial rather than a direct call. Something like %foo($a, $b, ?), to indi= cate that we were partially applying the function rather than calling it= . I don't know if that would actually work, especially if combined with= some simplified set of capabilities for better auto-partialing. These questions are not immediately part of the topic of this thread, bu= t they're closely-related topics that should be considered when designin= g them. --Larry Garfield