Newsgroups: php.internals
Path: news.php.net
Xref: news.php.net php.internals:126342
X-Original-To: internals@lists.php.net
Delivered-To: internals@lists.php.net
Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5])
	by qa.php.net (Postfix) with ESMTPS id F17A11A00BC
	for <internals@lists.php.net>; Fri,  7 Feb 2025 21:04:34 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail;
	t=1738962109; bh=ZYCXcGaKFMOsDF4w+rLsVlm51bXG2wkUW5IKC1NHGao=;
	h=Date:From:To:In-Reply-To:References:Subject:From;
	b=mepHMMgPtMhXZ+YWlC1CqU6h67hT1wzb98tMPSFrrEpHxNj1G2E0MEMEch+o93DK+
	 1zXqEzgR7Ai8ImmUR6WAolqsjrGAd/EjJAJt3z9LKUTNJafIb4t9VpKDSxwJy2CLeb
	 dUmfdQguTBEs8YfvvulX1OflTVWCnj+jAa3niKX+Pj0tWGKbIm3CbrDNbjjpKJnWGc
	 HEs+TYclwv9L6lVfSO4wa8onmaMezyAybtlJiXC2qf5pM96iBSph31OThfTeA6Pbph
	 EzTTY/tltr4prtTNp0JKGs9HQB3Bn/CwUEX+puOBxgHtIGDIBflLZP/K2qORzH6B/U
	 +ov/OM+GMbrSA==
Received: from php-smtp4.php.net (localhost [127.0.0.1])
	by php-smtp4.php.net (Postfix) with ESMTP id CF845180086
	for <internals@lists.php.net>; Fri,  7 Feb 2025 21:01:48 +0000 (UTC)
X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-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,DMARC_MISSING,RCVD_IN_DNSWL_LOW,
	SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=4.0.0
X-Spam-Virus: No
X-Envelope-From: <larry@garfieldtech.com>
Received: from fout-b8-smtp.messagingengine.com (fout-b8-smtp.messagingengine.com [202.12.124.151])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256)
	(No client certificate requested)
	by php-smtp4.php.net (Postfix) with ESMTPS
	for <internals@lists.php.net>; Fri,  7 Feb 2025 21:01:48 +0000 (UTC)
Received: from phl-compute-01.internal (phl-compute-01.phl.internal [10.202.2.41])
	by mailfout.stl.internal (Postfix) with ESMTP id A201D11400FD
	for <internals@lists.php.net>; Fri,  7 Feb 2025 16:04:32 -0500 (EST)
Received: from phl-imap-06 ([10.202.2.83])
  by phl-compute-01.internal (MEProxy); Fri, 07 Feb 2025 16:04:32 -0500
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=
	garfieldtech.com; h=cc:content-transfer-encoding:content-type
	:content-type:date:date:from:from:in-reply-to:in-reply-to
	:message-id:mime-version:references:reply-to:subject:subject:to
	:to; s=fm3; t=1738962272; x=1739048672; bh=t3TZNPRe+6jNwcGpwqIY+
	hsKJeVrBeKUbDo1G/a/wdQ=; b=AwpYS7ywl3ALkvYsf6FxSUzgS+SD2QcCZ6dv7
	wplx+h8jHToG4MeQkkRYDuEdkxJFGS2mDmJM5CPnyysMCD2Dm9+ZP27ZkWSskmct
	kKlSOcz2LKbXl8e6Ua8TZQ/hf5q5KF/3SeuU3ahIBLtblTQtEMX0IoUg+pTmd/J6
	zDpQDsXMJyiwh9D0ZjQYyG1ku9Dn49MzU9nbT49Fvt6y/SXeQ3Hx9kynvbkuoJkS
	nVS51SiG79UzKo7Ardh3qhps9bJjItv1bkQHE9tl9c2sflB7rufuLkiKa/4hz6Cd
	EfAqKR9STooMM7QacI7RGCSKJgUdaFjuu8VlJHnSVHLQQZZQw==
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=
	messagingengine.com; h=cc:content-transfer-encoding:content-type
	:content-type:date:date:feedback-id:feedback-id:from:from
	:in-reply-to:in-reply-to:message-id:mime-version:references
	:reply-to:subject:subject:to:to:x-me-proxy:x-me-sender
	:x-me-sender:x-sasl-enc; s=fm3; t=1738962272; x=1739048672; bh=t
	3TZNPRe+6jNwcGpwqIY+hsKJeVrBeKUbDo1G/a/wdQ=; b=NuhWqxwTISHQTiBvO
	ZQ4WwNHQJldnj16brskUsw1UT1NTETlPtyfuYJH2FxqdyewNEwbUoVG3VIQH16jS
	VgqNHYAqcvRwKYoYhvSQhCe1KutlCwP02wbEtYWuAXrrCz8y0G0A4wV/IaRx2ZQO
	hewSg94tjp8xEwHwGjh3kSAHTdUiDCO7ANpTNECIMumh2w/eURw1hlRs2wVsyDpo
	+9L5mlUWamIC76Ge8/cPRSboK03Z4RYeskbVWozNQdOM3auklSyofMIOIEc5poTa
	DRzDF/Azzjwlo9/9GYefWSkI4uSwXQ8t+iyOkpRhHeqaqa0193Y0V3g6An58Td83
	dSpSg==
X-ME-Sender: <xms:YHWmZ0xhjsJryKyKPnhrvfcwQa4tp5WD4lfZBjLulYNjT3tpU8_yFQ>
    <xme:YHWmZ4TRD6SIhFVc5Ava72sPw_U0eXXUD86-a04uHNdTR6MTHebVxlvpPut0YlkdW
    WJ79S9AjzIUjQ>
X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdeftdefvdcutefuodetggdotefrod
    ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdp
    uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivg
    hnthhsucdlqddutddtmdenucfjughrpefoggffhffvkfgjfhfutgfgsehtqhertdertdej
    necuhfhrohhmpedfnfgrrhhrhicuifgrrhhfihgvlhgufdcuoehlrghrrhihsehgrghrfh
    hivghlughtvggthhdrtghomheqnecuggftrfgrthhtvghrnhepleduvdduleekieejkeeu
    kefgvdeifeelveevjeefhfeftdeugfduieeuheffleeknecuffhomhgrihhnpehphhhprd
    hnvghtpdhgihhthhhusgdrtghomhenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgr
    mhepmhgrihhlfhhrohhmpehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomhdpnh
    gspghrtghpthhtohepuddpmhhouggvpehsmhhtphhouhhtpdhrtghpthhtohepihhnthgv
    rhhnrghlsheslhhishhtshdrphhhphdrnhgvth
X-ME-Proxy: <xmx:YHWmZ2UlCabjm3HkqNSLo9snPIfg2KSVjlxcyCFoRc7Fj50JLmz8qQ>
    <xmx:YHWmZygWfT2X9kFFBHNyEF1Y6H-0QwCw9ooYAfVDmVg2z83SSXsU-A>
    <xmx:YHWmZ2AjTukWMGu4Wiz2pbqvh03mkc1kC7bvDNnHwsx8tyLBpV4s_Q>
    <xmx:YHWmZzLsc-caTZe0ULIHZ4bLEbB1SU6_GqScy5w3nHddWFJ5e7utng>
    <xmx:YHWmZ98wA62SYzM6heGcHGlZPZ6jzWxX6dBg02Wti5YIMpA4SPY92geM>
Feedback-ID: i8414410d:Fastmail
Received: by mailuser.phl.internal (Postfix, from userid 501)
	id EFCB129C006F; Fri,  7 Feb 2025 16:04:31 -0500 (EST)
X-Mailer: MessagingEngine.com Webmail Interface
Precedence: bulk
list-help: <mailto:internals+help@lists.php.net
list-unsubscribe: <mailto:internals+unsubscribe@lists.php.net>
list-post: <mailto:internals@lists.php.net>
List-Id: internals.lists.php.net
x-ms-reactions: disallow
MIME-Version: 1.0
Date: Fri, 07 Feb 2025 15:04:11 -0600
To: "php internals" <internals@lists.php.net>
Message-ID: <bd93bbb9-e970-4211-af59-4ccd643dc52f@app.fastmail.com>
In-Reply-To: <5a584219f120385e7e30f6d0a46cc108@bastelstu.be>
References: <de8140ab-0941-45cd-ba20-4aece2f69aea@app.fastmail.com>
 <5a584219f120385e7e30f6d0a46cc108@bastelstu.be>
Subject: Re: [PHP-DEV] [RFC] Pipe Operator (again)
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
From: larry@garfieldtech.com ("Larry Garfield")

Merging a few replies together here, since they overlap.  Also reorderin=
g a few of Tim's comments...

On Fri, Feb 7, 2025, at 7:32 AM, Tim D=C3=BCsterhus wrote:
> Hi
>
> Am 2025-02-07 05:57, schrieb Larry Garfield:
>> It is now back with a better implementation (many thanks to Ilija for=20
>> his help and guidance in that), and it's nowhere close to freeze, so=20
>> here we go again:
>>=20
>> https://wiki.php.net/rfc/pipe-operator-v3
>
> There's some editorial issues:
>
> 1. Status: Draft needs to be updated.
> 2. The RFC needs to be added to the overview page.
> 3. List formatting issues in =E2=80=9CFuture Scope=E2=80=9D and =E2=80=
=9CPatches and Tests=E2=80=9D.
>
> Would also help having a closed voting widget in the =E2=80=9CProposed=
 Voting=20
> Choices=E2=80=9D section to be crystal clear on what is being voted on=
 (see=20
> below the next quote).

I split pipes off from the Composition RFC late last night right before =
posting; I guess I missed a few things while doing so. :-/  Most notably=
, the Compose section is now removed from pipes, as it is not in scope f=
or this RFC.  (As noted, it's going to be more work so has its own RFC.)=
  Sorry for the confusion.  I think it should all be handled now.

> 5. The =E2=80=9CReferences=E2=80=9D (as in reference variables) sectio=
n would do well=20
> with an example of what doesn't work.

Example block added.

> 9. In the =E2=80=9CWhy in the engine?=E2=80=9D section: The RFC makes =
a claim about=20
> performance.
>
> Do you have any numbers?

Not currently.  The statements here are based on simply counting the num=
ber of function calls necessary, and PHP function calls are sadly non-ch=
eap.  In previous benchmarks of my own libraries using my Crell/fp libra=
ry, I did find that the number of function calls involved in some tight =
pipe operations was both a performance and debugging concern, but I don'=
t have any hard numbers laying about at present to share.

If you think that's critical, please advise on how to best get meaningfu=
l numbers here.

Regarding the equivalency of pipes:

Tim D=C3=BCsterhus wrote:
> 4. =E2=80=9CThat is, the following two code fragments are also exactly=20
> equivalent:=E2=80=9D.
>
> I do not believe this is true (specifically referring to the =E2=80=9C=
exactly=E2=80=9D=20
> word in there), since the second code fragment does not have the short=20
> closures, which likely results in an observable behavioral difference=20
> when throwing Exceptions (in the stack trace) and also for debuggers. =
Or=20
> is the implementation able to elide the the extra closure? (Of course=20
> there's also the difference between the temporary variable existing,=20
> with would be observable for `get_defined_vars()` and possibly=20
> destructors / object lifetimes).

Thomas Hruska wrote:
> The repeated assignment to $temp in your second example is _not_=20
> actually equal to the earlier example as you claim.  The second exampl=
e=20
> with all of the $temp variables should, IMO, just be:
>
> $temp =3D "Hello World";
> $result =3D array_filter(array_map('strtoupper',=20
> str_split(htmlentities($temp))), fn($v) { return $v !=3D 'O'; });

Juris Evertovskis wrote:
> 3. Does the implementation actually turn `1 |> f(...) |> g(...)` into=20
> `$=CF=80 =3D f(1); g($=CF=80)`? Is `g(f(1))` not performanter? Or is t=
he engine=20
> clever enough with the var reuse anyways?

There's some subtlety here on these points.  The v2 RFC used the lexer t=
o mutate $a |> $b |> $c into the same AST as $c($b($a)), which would the=
n compile as though that had been written in the first place.  However, =
that made addressing references much harder, and there's an important ca=
veat around order of operations. (See below.)  The v3 RFC instead uses a=
 compile function to take the AST of $a |> $b |> $c and produce opcodes =
that are effectively equivalent to $t =3D $b($a); $t =3D $c($t);  I have=
 not compared to see if they are the precise same opcodes, but they net =
effect is the same.  So "effectively equivalent" may be a more accurate =
statement.

In particular, Tim is correct that, technically, the short lambdas would=
 be used as-is, so you'd end up with the equivalent of:

$temp =3D (fn($x) =3D> array_map(strtoupper(...), $x))($temp);

I'm not sure if there's a good way to automatically unwrap the closure t=
here.  (If someone knows of one, please share; I'm fine with including i=
t.)  However, the intent is that it would be largely unnecessary in the =
future with a revised PFA implementation, which would obviate the need f=
or the explicit wrapping closure.  You would instead write

$a |> array_map(strtoupper(...), ?);

Alternatively, one can use higher order user-space functions already.  I=
n trivial cases:

function amap(Closure $fn): Closure {
  return fn(array $x) =3D> array_map($fn, $x);
}

$a |> amap(strtoupper(...));

Which I am already using in Crell/fp and several libraries that leverage=
 it, and it's quite ergonomic.

There's a whole bunch of such simple higher order functions here:
https://github.com/Crell/fp/blob/master/src/array.php
https://github.com/Crell/fp/blob/master/src/string.php

Which leads to the subtle difference between that and the v2 implementat=
ion, and why Thomas' statement is incorrect.  If the expression on the r=
ight side that produces a Closure has side effects (output, DB interacti=
on, etc.), then the order in which those side effects happen may change =
with the different restructuring.  With all pure functions, that won't m=
ake a practical difference, and normally one should be using pure functi=
ons, but that's not something PHP can enforce.

I don't think there would be an appreciable performance difference betwe=
en the two compiled versions, either way, but using the temp-var approac=
h makes dealing with references easier, so it's what we're doing.

Juris Evertovskis wrote:
> 1. Do you think it would be hard to add some shorthand for `|>=20
> $condition ? $callable : fn($=F0=9F=98=90) =3D> $=F0=9F=98=90`?

I'm not sure I follow here.  Assuming you're talking about "branch in th=
e next step", the standard way of doing that is with a higher order user=
-space function.  Something like:

function cond(bool $cond, Closure $t, Closure $f): Closure {
  return $cond ? $t : $f;
}

$a |> cond($config > 10, bigval(...), smallval(...)) |> otherstuff(...);

I think it's premature to try and bake that logic into the language, esp=
ecially when I don't know of any other function-composition-having langu=
age that does so at the language level rather than the standard library =
level.  (There are a number of fun operations people build into pipeline=
s, but they are all generally done in user space.)

--Larry Garfield