Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118921 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 84811 invoked from network); 30 Oct 2022 20:26:01 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 30 Oct 2022 20:26:01 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 017D318004D for ; Sun, 30 Oct 2022 13:26:00 -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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS24940 176.9.0.0/16 X-Spam-Virus: No X-Envelope-From: Received: from chrono.xqk7.com (chrono.xqk7.com [176.9.45.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 30 Oct 2022 13:26:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bastelstu.be; s=mail20171119; t=1667161558; bh=qL1S1uRy1+EC8P/76Pf8NZcjB1cKn5ymmtv9uUeBJSk=; h=Date:Subject:To:References:From:In-Reply-To:From; b=jKEZqPs6GdkxXYvPHoZshTp5bJq4LM7zg3BZRH9rWQ+b72M6mV+LzeYE1Ui7CSEy+ pVmy8jU82rVlC/9zTHHGYlRFIyQ9pnqOLFtYAnbqaPqD6SXJ/Xt88RJA0rMYcU0vOa smB9jtbt4O5X1deQVXXlBsObdTp+9PzMm5ho3rAPhrz3uvYwwO+Rcc/oSSaOVZjwL8 HySbN7vap48akMNXCmkBM+uQBF2IxobGL8+SfLThoDthlNh31ISVDpCQRWzuoh5GJM sl+lZfMcXQnOotoVpIJsA6MHChy5fAklnRiz6N2Tlvy0sXZcPtISZikUcHPlgDUnaU uZ5aTJCT963TQ== Message-ID: <0226a847-2a07-8909-68a9-a802756db108@bastelstu.be> Date: Sun, 30 Oct 2022 21:25:56 +0100 MIME-Version: 1.0 Content-Language: en-US To: Larry Garfield , php internals References: <960d38a8-c2ad-4cd3-9041-ce42aa38bd18@app.fastmail.com> In-Reply-To: <960d38a8-c2ad-4cd3-9041-ce42aa38bd18@app.fastmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Subject: Re: [PHP-DEV] Proposal: Expanded iterable helper functions and aliasing iterator_to_array in `iterable\` namespace From: tim@bastelstu.be (=?UTF-8?Q?Tim_D=c3=bcsterhus?=) Hi On 10/30/22 17:22, Larry Garfield wrote: > 2. There are ample use cases for most operations to return an array or a lazy iterable. Both totally exist. I solved that by also having a separate version of each function, eg, amap() vs itmap(). The former returned an array, the latter returned a generator that generated the equivalent 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 giving any further guarantees, because … > A possible alternative would be to always return a lazy iterable in all 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 performance impact since generators are slower than plain arrays. … this works. The users should not need to think about what return type is more useful for their specific use case. The heavy lifting / optimization should be left to the compiler / engine, similarly how a fully qualified 'is_null()' is also optimized, such that no actual function call happens [1]. Even if this kind of optimization does not happen in the first version, this should not be a reason to clutter the API surface. > 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, though, that all are designed to be used with a pipe(), so they mostly return a closure that has been manually partially applied with everything except the iterable, so you get a single-argument function, which is what a pipe() or compose() chain needs. > > Third, speaking of pipe, I disagree with Tim that putting the callback first would be easier for pipe/partials. If we ever get partials similar 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. > > The alternative I've considered is somewhat inspired by Elixir (assuming I understand the little Elixir I've read), in which a function after a |> is automatically assumed to be partially applying everything but the 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 functions took the iterable, the "object to be operated on", as their first argument. > With Haskell, from which my functional programming experience comes, it's the exact inverse: All functions are automatically partially applied [2], thus in a pipe the "missing" parameter comes last, not first as with Elixir. So I guess there is no right or wrong and it depends on the programming language which variant feels more natural. I still prefer having the callback first for the reasons I've outlined, but in the end I'm happy as long as it's consistent. Best regards Tim Düsterhus [1] https://github.com/php/php-src/blob/e00dadf43a17da3bb79aba360d07e29b359c12b3/Zend/zend_compile.c#L4372-L4373 [2] You can just do 'lengthOfAll = map length' and then 'lengthOfAll ["foo", "bar", "foobar"]'