Re: [RFC] Partial Function Application v2

From: Date: Sun, 12 Oct 2025 18:35:11 +0000
Subject: Re: [RFC] Partial Function Application v2
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to internals+get-128820@lists.php.net to get a copy of this message
Hi On 10/10/25 17:26, Larry Garfield wrote:
What will happen if the original function already has a parameter named $args0?
It will skip over existing names. I've updated the text accordingly.
Okay. Looking at all the examples, I think it would be nice if it would not use the generic arg prefix, but use the original name as the prefix. For the
    function foo(int $a = 5, int $b = 1, string ...$c) { }
example, the 3rd and following parameters could be $c_1, $c_2, … (still skipping over duplicates).
Prefill all parameters, making a "delayed call" or "thunk"
The example desugaring is inconsistent with the previously explained semantics: Here an arbitrary number of arguments is accepted, but previously it says "will result in a Closure with no parameters".
Hm, I think that should probably read "no required parameters". It would only make a difference if the underlying function had an optional variadic AND you called the thunk with extra, extraneous args.
Okay. Now looking at the examples:
    $c = stuff(?, ?, f3: 3.5, p4: $point, ...);
    $c = fn(int $i1, string $s2, int $m5 = 0): string => stuff($i1, $s2, 3.5, $point, $m5);
and
    $c = stuff(1, 'hi', 3.4, $point, 5, ...);
    $c = fn(...$args): string => stuff(1, 'hi', 3.4, $point, 5, ...$args);
seem to be inconsistent with each other with regard to whether or not "superfluous" arguments are passed through. This might (or might not?) be explained in the “func_get_args() and friends” section, but is unexplained at the point the example appears. Also within the func_get_args() section, there is no explicit ...$args in the resulting signature, but instead the desugaring uses array_slice() + func_get_args().
- Are PFAs legal in constant expressions? e.g. does the following work: const Foo = intval(?, 10);?
At the moment no, though Arnaud says that should be doable, with some reasonable restrictions. (No variables, no variable callable name, etc.)
Yes, restrictions go without saying. The support for FCC in const-expr also doesn't support variable names and Closures in const-expr may also not capture the scope.
I've asked Arnaud to generate one for the RFC.
Thank you, I'm seeing you added an example. I've a small request to hopefully make the example more useful: It currently uses only “placeholder” parameters. It would be useful to also add one pre-filled parameter to it. I would assume that this pre-filled parameter does not appear within the Closure frame, but appears with the frame for the actual function? Relatedly to the stack trace example and also to the “Evaluation order” I'd be curious how pre-filled parameters are implemented technically. For pre-filled variables, the regular variable capturing logic would work, but it doesn't for function returns. Is it effectively creating a temporary variable under the hood? Meaning is:
    $partial = speak(?, getArg());
desugared into:
    $pfa_tmp_2 = getArg();
    $partial = fn (string $who) => speak($who, $pfa_tmp2);
? - How does it interact with compact(), specifically:
    $partial = compact(someValue(), ?);
Would the ? be able to capture a variable containing the return value of someValue()? - How does it interact with ReflectionFunctionAbstract::getClosureUsedVariables()? - Same question for other scope introspection functionality (e.g. Xdebug). Best regards Tim Düsterhus

« previous php.internals (#128820) next »