Re: Pipe precedence challenges

From: Date: Fri, 22 Aug 2025 09:40:46 +0000
Subject: Re: Pipe precedence challenges
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-128524@lists.php.net to get a copy of this message
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 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 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) => ($x > > |> (fn($x) => array_map(strtoupper(...), $x)) > > |> (fn($x) => array_filter($x, fn($v) => $v != 'O')) > > ); > > > > Proposed "canned pipes" syntax: > > ------------------------------- > > > > fn($x) => > > |> array_map(strtoupper(...), $x) > > |> array_filter($x, fn($v) => $v != 'O') > > ; > > > > > > This syntax: > > > > * Resolves the ambiguity: The fn($x) => explicitly > > "cans" the value > > for the entire pipe chain, making the precedence clear without > > parentheses. > > > > * Reduces boilerplate: It eliminates the repetition of fn($x) > > => and > > nested parentheses, making the code more readable and maintainable. > > > > * Aligns with intent: It reads as a simple sequence of transformations, > > which is the core goal of the pipe operator. > > > > This 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 developer ergonomics and > > future-proofing. > > > > I understand that implementation feasibility needs to be assessed, but > > 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 > > 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 not when a pipe is inside a closure, but when a closure is inside a > pipe, which is likely the far more common case. > > $input > |> fn($x) => array_map(strtoupper(...), $x) > |> fn($x) => array_filter($x, fn($v) => $v != 'O') > ; > > The problem is this gets interpreted "backwards", with the first closure wrapping > around second, rather than being a sibling of it in a pipe chain. A short-hand for > pipes-in-closures wouldn't address this issue, which is the more pressing concern. > > The annoying extra parens there would also be resolved using PFA, which 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.) > > --Larry Garfield > 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) => |> array_map(strtoupper(...), $x) |> array_filter($x, fn($v) => $v != 'O'); — Rob

« previous php.internals (#128524) next »