Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128524 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 lists.php.net (Postfix) with ESMTPS id 407F21A00BC for ; Fri, 22 Aug 2025 09:41:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1755855578; bh=fS7zGvKf/8ejyqUtP9AY7bbApWupScc8UKdOh1KMvNs=; h=Date:From:To:In-Reply-To:References:Subject:From; b=II117fgN3xvUIZprPFwajCkup4AxJX2/2JOo0w0txrYjsGc8I8qgnbrejqjwSohAQ a780RxFga1CuXRdGNdGgW34EEvBNzvntasaIr5of/BdPOYbB6ivLKIBYr+VKnoCQMU 6kANLb2c/1KRSkEAPfMJjMUKpfD5l0gd2tpm38jvYUcRFs23C3pvU6wdsDqF/IDq/M yXtrDgWeEYpZfd6/sdhZsdkuhIPyX/qMhqYGJowWmHi9Re2RUQeedXsvJmXRUMHB3D I6nJge/29bfeLGTxEISLoODt8jtmv/HJWzEXSZcrHWFGwNkixMkbukYABtPhwND2Z3 hJfRyUm83PqgQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 873AA18004D for ; Fri, 22 Aug 2025 09:39:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) 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,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: No X-Envelope-From: Received: from fout-b4-smtp.messagingengine.com (fout-b4-smtp.messagingengine.com [202.12.124.147]) (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 ; Fri, 22 Aug 2025 09:39:34 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id C56701D0022E for ; Fri, 22 Aug 2025 05:41:07 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Fri, 22 Aug 2025 05:41:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc: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=fm1; t=1755855667; x=1755942067; bh=nzJwHlARcZ 0Qab35Z2sfES+dWdDtKDwE22yiZ5g2gmU=; b=JNLUvApNVQz8zUG/uf1FvSpqOv 90IiV1J1+XiCWV0FcYkqbmGe2p+utPyWlQuD69vK8FYnr57VWoSSHCnSn9If7NDs 2Fv/qO4kF2F1jevn9WaXtsONQxoUzmgLeBy39/faAP0MjldP+3CoRD/f2GUxQxVe dV+/3yFxdKDj9bVs44vnhLfffz8wZEbiIPOJ+dnGNTkdoR173bEyVgQonCrO+mnd 4FI0ppjWYO4pai5wfsD1VolP89w5eh6nstAJjmDU4/YrWE9kwAWzac9oh8VOzhJ3 /iU/zS+8z/sUUFCcGY3Q1wIwky+w0WXLT+9LR5chIEOLUk/PKIS2r85SctxA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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= 1755855667; x=1755942067; bh=nzJwHlARcZ0Qab35Z2sfES+dWdDtKDwE22y iZ5g2gmU=; b=fszMb31RclF3Pg6nWAIGsIgf6d3Ei+3wuid2an07dmJVopG7S+Y vJ6499891FQrUbabMd7Eq7GY1HW9xjpa6AOuWBIEZ7mGlqd7MrBnUDlO1wcWeNvF 5EMQzIFY/Vxgv7/m+uikHy3NQNjYAKH5zWauO+imjAZnbKGW/Mr1BnbVwaJ+cGjm Yi7z+KO8dKEaHswWRT8L+HaxY3ldqZzdQr5hE5OZCBK8BkKaWtutNVlpm+axsHqP xV5DHwjoMD/EpjmhXFHVWatSEPoc38h/DVv3N+vUiyHGZzSRhIyrix1Srk6Yzmb9 zk5k50M+0ivS1s9GYsFEaB6cjYkSDB/6WXg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdduieefgedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucenucfjughrpefoggffhffvkfgjfhfutgesrgdtreerre dtjeenucfhrhhomhepfdftohgsucfnrghnuggvrhhsfdcuoehrohgssegsohhtthhlvggu rdgtohguvghsqeenucggtffrrghtthgvrhhnpeelkeehtdfgfefhleeilefggeeihfekvd elfeejtdfflefhheehfffgudetuddutdenucffohhmrghinhepphhhphdrnhgvthenucev lhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehrohgssegsoh htthhlvggurdgtohguvghspdhnsggprhgtphhtthhopedupdhmohguvgepshhmthhpohhu thdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 2E59E1820074; Fri, 22 Aug 2025 05:41:07 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: A7rib2RgmwtZ Date: Fri, 22 Aug 2025 11:40:46 +0200 To: internals@lists.php.net Message-ID: In-Reply-To: <08a0d032-b2f9-4bc6-b44d-f5a02b6ab376@app.fastmail.com> References: <1755766483699.1651677569.3151523711@yahoo.de> <08a0d032-b2f9-4bc6-b44d-f5a02b6ab376@app.fastmail.com> Subject: Re: [PHP-DEV] Pipe precedence challenges Content-Type: multipart/alternative; boundary=dc22a09666954d77af335b521250769c From: rob@bottled.codes ("Rob Landers") --dc22a09666954d77af335b521250769c Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Aug 21, 2025, at 15:53, Larry Garfield wrote: > On Thu, Aug 21, 2025, at 4:07 AM, Hans Krentel wrote: > > On Thursday 14 August 2025 21:30:08 (+02:00), Larry Garfield wrote: > > > >> Does anyone have a better solution to suggest? > > > > I've been following the discussion on the pipe/short-closure precede= nce > > issue, and while the parentheses-based solution works, it does lead = to > > syntactic noise that undermines the readability benefits of pipes. > > > > I'd like to suggest an alternative that turns this problem into an > > opportunity for a more elegant syntax. > > > > Inspired by prior art like Haskell's `do` notation, I propose what I > > call "short closure canned pipes." The idea is to leverage the greedy > > nature of short closures to define a clean, linear pipe chain within= a > > closure context. Instead of fighting the precedence, we embrace it = to > > create a new form: > > > > > > Current problematic example (even with parentheses): > > ---------------------------------------------------- > > > > fn($x) =3D> ($x > > |> (fn($x) =3D> array_map(strtoupper(...), $x)) > > |> (fn($x) =3D> array_filter($x, fn($v) =3D> $v !=3D 'O')) > > ); > > > > Proposed "canned pipes" syntax: > > ------------------------------- > > > > fn($x) =3D> > > |> array_map(strtoupper(...), $x) > > |> array_filter($x, fn($v) =3D> $v !=3D 'O') > > ; > > > > > > This syntax: > > > > * Resolves the ambiguity: The `fn($x) =3D>` explicitly "cans" the va= lue > > for the entire pipe chain, making the precedence clear without > > parentheses. > > =20 > > * Reduces boilerplate: It eliminates the repetition of `fn($x) =3D>`= and > > nested parentheses, making the code more readable and maintainable. > > =20 > > * Aligns with intent: It reads as a simple sequence of transformatio= ns, > > which is the core goal of the pipe operator. > > =20 > > This approach effectively provides syntactic sugar for the common ca= se > > of processing a value through a pipe chain within a closure. It turns > > the late-discovered defect into a win for developer ergonomics and > > future-proofing. > > > > I understand that implementation feasibility needs to be assessed, b= ut > > if possible, this could be a more satisfying solution than mandatory > > parentheses. Thanks to the team for highlighting this issue -- it's > > sparked a creative way to enhance the feature. > > > > Would love to hear thoughts on this. > > > > Best, > > hakre >=20 > That's an interesting idea, but I don't think it solves the problem. >=20 > It would make the syntax for pipes-in-closures nicer, yes. However: >=20 > 1. Ideally, I'm hoping such a pipe-in-closure is replaced with a Compo= sition operator soon enough (https://wiki.php.net/rfc/function-compositi= on), so that wouldn't even be necessary. > 2. The main problem is not when a pipe is inside a closure, but when a= closure is inside a pipe, which is likely the far more common case. >=20 > $input > |> fn($x) =3D> array_map(strtoupper(...), $x) > |> fn($x) =3D> array_filter($x, fn($v) =3D> $v !=3D 'O') > ; >=20 > The problem is this gets interpreted "backwards", with the first closu= re wrapping around second, rather than being a sibling of it in a pipe c= hain. A short-hand for pipes-in-closures wouldn't address this issue, w= hich is the more pressing concern. >=20 > The annoying extra parens there would also be resolved using PFA, whic= h side steps the arrow function in the common case. As the issue is the= syntactic parsing of arrow functions, not having arrow functions would = also resolve the issue. (As would using higher-order functions instead,= which frankly is what I am likely to do 90% of the time myself.) >=20 > --Larry Garfield >=20 I think the point Hans was making is that the fn($x) becomes implicit so= you don't even need it, so your example would be something like this in= this case: $input |> fn($x) =3D> |> array_map(strtoupper(...), $x) |> array_filter(= $x, fn($v) =3D> $v !=3D 'O'); =E2=80=94 Rob --dc22a09666954d77af335b521250769c Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Thu, Aug = 21, 2025, at 15:53, Larry Garfield wrote:
On Thu, Aug 21, 2025, at 4:07 AM, Hans Krente= l wrote:
> On Thursday 14 August 2025 21:30:08 (+02:00), La= rry Garfield wrote:
>
>> Does anyone have a= better solution to suggest?
>
> I've been fol= lowing the discussion on the pipe/short-closure precedence
>= ; issue, and while the parentheses-based solution works, it does lead to=
> syntactic noise that undermines the readability benefits= of pipes.
>
> I'd like to suggest an alternat= ive that turns this problem into an
> opportunity for a mor= e elegant syntax.
>
> Inspired by prior art li= ke Haskell's `do` notation, I propose what I
> call "short = closure canned pipes." The idea is to leverage the greedy
>= nature of short closures to define a clean, linear pipe chain within a<= /div>
> closure context.  Instead of fighting the precedence= , we embrace it to
> create a new form:
>
>
> Current problematic example (even with parenth= eses):
> --------------------------------------------------= --
>
>     fn($x) =3D> = ($x
>     |> (fn($x) =3D> array_m= ap(strtoupper(...), $x))
>     |> (f= n($x) =3D> array_filter($x, fn($v) =3D> $v !=3D 'O'))
&g= t;     );
>
> Proposed "ca= nned pipes" syntax:
> -------------------------------
=
>
>     fn($x) =3D>
>     |> array_map(strtoupper(...), $x)
>     |> array_filter($x, fn($v) =3D>= $v !=3D 'O')
>     ;
>
>
> This syntax:
>
> *= Resolves the ambiguity: The `fn($x) =3D>` explicitly "cans" the valu= e
>   for the entire pipe chain, making the prece= dence clear without
>   parentheses.
&g= t;  
> * Reduces boilerplate: It eliminates the r= epetition of `fn($x) =3D>` and
>   nested pare= ntheses, making the code more readable and maintainable.
>&= nbsp; 
> * Aligns with intent: It reads as a simple se= quence of transformations,
>   which is the core = goal of the pipe operator.
>  
> Thi= s approach effectively provides syntactic sugar for the common case
> of processing a value through a pipe chain within a closure. = It turns
> the late-discovered defect into a win for develo= per ergonomics and
> future-proofing.
>
<= div>> I understand that implementation feasibility needs to be assess= ed, but
> if possible, this could be a more satisfying solu= tion than mandatory
> parentheses.  Thanks to the team= for highlighting this issue -- it's
> sparked a creative w= ay to enhance the feature.
>
> Would love to h= ear thoughts on this.
>
> Best,
>= hakre

That's an interesting idea, but I don't = think it solves the problem.

It would make the = syntax for pipes-in-closures nicer, yes.  However:

1. Ideally, I'm hoping such a pipe-in-closure is replaced with = a Composition operator soon enough (https://wiki.php.net/rfc/function-composition)= , so that wouldn't even be necessary.
2. The main problem is n= ot when a pipe is inside a closure, but when a closure is inside a pipe,= which is likely the far more common case.

$inp= ut
     |> fn($x) =3D> array_map(str= toupper(...), $x)
     |> fn($x) =3D>= ; array_filter($x, fn($v) =3D> $v !=3D 'O')
;
The problem is this gets interpreted "backwards", with the f= irst closure wrapping around second, rather than being a sibling of it i= n a pipe chain.  A short-hand for pipes-in-closures wouldn't addres= s this issue, which is the more pressing concern.

The annoying extra parens there would also be resolved using PFA, whi= ch side steps the arrow function in the common case.  As the issue = is the syntactic parsing of arrow functions, not having arrow functions = would also resolve the issue.  (As would using higher-order functio= ns instead, which frankly is what I am likely to do 90% of the time myse= lf.)

--Larry Garfield


I think the point Hans was making is that th= e fn($x) becomes implicit so you don't even need it, so your example wou= ld be something like this in this case:

$in= put |> fn($x) =3D> |> array_map(strtoupper(...), $x) |> arra= y_filter($x, fn($v) =3D> $v !=3D 'O');


<= /div>

=E2=80=94 Rob
<= /html> --dc22a09666954d77af335b521250769c--