Hi

On 2/7/25 22:04, Larry Garfield wrote:
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 for 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.

The “Introduction” section still talks about function composition rather than the pipe operator, I believe.

5. The “References” (as in reference variables) section would do well
with an example of what doesn't work.

Example block added.

I don't understand that example. If I would write this as regular function calls it works fine. Did you mean to compare against:

    inc_print(['a' => 'A', 'b' => 'B']);

i.e.

    ['a' => 'A', 'b' => 'B'] |> inc_print(...);

? If not, then you will need to expand on “breaks” which is a non-technical term.

9. In the “Why in the engine?” section: The RFC makes a claim about
performance.

Do you have any numbers?

Not currently.  The statements here are based on simply counting the number of 
function calls necessary, and PHP function calls are sadly non-cheap.  In 
previous benchmarks of my own libraries using my Crell/fp library, 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 meaningful 
numbers here.

Not sure if I missed the dedicated performance section on my first read through the RFC or if it is actually new. It also claims:

> The result is that pipe has virtually no runtime overhead.

Which given your claim that “function calls are non-cheap” and combined with the intermediate closure for calls taking more than one parameter is contradictory.

Generally speaking, if your RFC makes a claim (about performance), then it needs to back this up by evidence and not with feelings.

Regarding the “How”:

A hyperfine (https://tideways.com/profiler/blog/how-we-use-hyperfine-to-measure-php-engine-performance) comparison for a release build comparing:

1. An implementation based on regular function calls without intermediate variables. 2. An implementation based on regular function calls with an intermediate temporary variable.
3. A performance-optimized userland pipe operator implementation.
4. The pipe operator RFC.

would certainly appropriate to gain a first insight.

Having an OPcode dump to compare (1) against (4) would help gain more insights as to where the performance differences come from.

If the expression on the right side that produces a Closure has side effects 
(output, DB interaction, etc.), then the order in which those side effects 
happen may change with the different restructuring.

That is a good point. I see you added a precedence section, but this does not fully explain the order of operations in face of side-effects and more generally with regard to “short-circuiting” behavior. An OPcode dump would explain that.

Specifically for:

    function foo()     { echo __FUNCTION__, PHP_EOL; return 1; }
    function bar()     { echo __FUNCTION__, PHP_EOL; return false; }
    function baz($in)  { echo __FUNCTION__, PHP_EOL; return $in; }
    function quux($in) { echo __FUNCTION__, PHP_EOL; return $in; }

    foo()
        |> (bar() ? baz(...) : quux(...))
        |> var_dump(...);

What will the output be?

but using the temp-var approach makes dealing with references easier

I thought the RFC said that references were disallowed?

Best regards
Tim Düsterhus

Reply via email to