On Wed, Jul 1, 2026, at 5:02 PM, Rowan Tommins [IMSoP] wrote:
> On 1 July 2026 20:02:27 BST, Seifeddine Gmati <[email protected]> 
> wrote:
>>Making `Closure` generic (e.g., say `Closure<Input, Output>` ) would
>>require `Input` to be variadic to stand in for a closure's parameter
>>list, and variadic generics are a different beast entirely.
>
> FWIW, C# has a long list of overloads for expressing generic lambda 
> types, like Action<T1,T2>, Action<T1,T2,T3>, Func<T1,T2,TResult> and so 
> on and on and on 
> <https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Action.cs>
>  
> <https://github.com/dotnet/dotnet/blob/b0f34d51fccc69fd334253924abd8d6853fad7aa/src/runtime/src/libraries/System.Private.CoreLib/src/System/Function.cs>
>
> Ugly, and unlikely to even work in a PHP implementation of generics.
>
> On the other hand, it has an elegant "delegate" syntax for what are 
> effectively named callable types: 
> https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/
>
> That *would* translate well to PHP. Translating one of their examples:
>
> delegate ProcessBookCallback(Book $book): void;
>
> public function processPaperbackBooks(ProcessBookCallback $processBook): void 
> { 
>     foreach ($this->list as $b) {
>         if ($b->paperback) {
>             $processBook($b);
>         }
>     }
> }
>
> Just an additional angle to throw into the mix.
>
>
> Rowan Tommins
> [IMSoP]

I am very much in favor of callable types, in concept.  (Which should surprise 
no one.)

I don't have very strong feelings on the spelling at the moment yet; I suspect 
this is a case where the parser will dictate to us what is possible, and that 
will greatly limit our options or just make the decision for us.  (That's how 
we ended up with fn() for short-closures.  It was the shortest thing the parser 
would let us get away with.)  

On the question of callable-vs-closure, I agree that today, between FCC and PFA 
a Closure is absolutely trivial to produce, so we don't need to support the 
variety of legacy callable formats.  The one caveat to that is for compiled 
code; you cannot store a closure in a serialized form or in generated code; 
functions and static methods are easy enough to store that way (as a string and 
array, respectively), ugly as those formats are.  Methods, anon functions, etc. 
however are much harder, and there's no globally standard way of cheating 
there.  I suspect the best we can do without scope creeping ourselves to death 
is just support closures and leave it to implementers to turn other callable 
formats into a closure, which isn't that hard these days.

Generics syntax is the wrong format to use for this, full stop.  Let's not even 
go down that pathway.  Generics are orthogonal.

The main semantic question is whether callable/closure types should be 
defineable inline, or only as a reference (as in Rowan's C# example above.)  In 
the past, there's been non-small pushback to defining them inline, as that can 
make for very hard to read function declarations and if the same signature is 
used in multiple places, you have to manually keep them in sync.

However, we don't have type aliases (yet), which would resolve that issue.  And 
when proposals have been floated to allow separate definition of a function 
interface (as Nicolas and I proposed), it's been rejected as too complicated.  
So we're really at an impasse on this.

My own stance is that we should just define them inline for now, and if that 
leads to messy function signatures then that's just all the more impetus for us 
to get off our butts and decide on a way to do type aliases. :-)  That's better 
than having a one-off syntax for function signature definition but something 
entirely different for complex union/intersection types, or restricted types 
(like "positive int"), etc.  Let's have all types inline-able, and then a 
globally-defined alias/reuse mechanism that supports all of them consistently.

The one should not block the other, especially not given how PHP Internals 
works.

--Larry Garfield

Reply via email to