On Mon, Jan 23, 2023, at 12:32 PM, Dan Ackroyd wrote:
> On Sun, 22 Jan 2023 at 17:45, Ollie Read <php@ollie.codes> wrote:
>>
>> Hello all,
>
> Hi Ollie,
>
>> I've created a feature request issue on GitHub (here: 
>> https://github.com/php/php-src/issues/10414), but I have been advised that 
>> it's best to post here.
>> ...
>> I think we could delay the error until the closure was called.
>
> That sounds like a complete non-starter. Adding something to the
> language that produces a closure that can't be called would be an
> instant new entry for PHPSadness.
>
>> Whereas it would be much nicer to have the following:
>>
>> ```
>> $collection->filter(Str::empty(...));
>> ```
>>
>> In this situation, the collection library would be responsible for binding 
>> the
>> closure to the value it is iterating.
>
> How would the collection library know it was safe to bind the closure
> to each value it was iterating over? It sounds really type unsafe.
>
>
>> What I would like to introduce/suggest, is the ability to create a closure
>> from a method using the first-class-callable syntax...
>>
>> The more I think about it, the more I think this may require a new ...
>
> I think people should say clearly what the problem they are trying to
> solve first, before suggesting solutions.
>
> I think there's at least a couple of problems that can be thought about:
>
> i. Although the first-class-callable syntax allowed avoiding string
> based programming for most callables, it doesn't support referring to
> some things that you would want to call, including both instance
> methods, and constructors*.
>
> ii. Representing an instance method requires at least two pieces of
> info; which class it belongs to (which can be used to find the
> constructor) and the parameters of the method itself. That doesn't
> naturally fit into a closure.
>
> iii. The appropriate syntax for referencing a class instance method
> without it being string based isn't obvious. Or at least it isn't
> obvious to me.
>
> iv. Writing code that for callback methods is longer than it could be,
> e.g. as Larry Garfield wrote:
>
>> So what you're really looking for is a shorter way to write this:
>>
>> foo(fn(Str $s) => $s->beep());
>
>
> At the risk of suggesting an abomination, given a class of:
>
> class Zoq
> {
>     public function __construct(private Fot $fot) {}
>
>     public function Pik(string $zebranky): Frungy {...}
> }
>
> If it was possible to generate callable for the constructor with:
>
> $fnConstructor = Closure::fromClassConstructor(Zoq::class);
> // signature of $fnConstructor is the same as `function(Fot $fot): Zoq`
>
> Or for individual methods:
>
> $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
> // signature of $fnMethod is the same as `function(Zoq $zoq, string
> $zebranky): Frungy`
>
> That sort of looks like a solution to most of the problems I think exist.
>
> For your particular problem, I believe that would allow:
>
> $fnMethod = Closure::fromClassMethod(Str::class, 'empty');
> $collection->filter($fnMethod);
>
> Which isn't shorter, but at least allows passing the callables around
> with the type inspectable. Though it might be nicer if PHP had the
> ability to definte function signatures types.
>
> That sort of solution obviously doesn't address the problem of having
> to refer to the class method as a string, but as I said, I don't have
> a suggestion for that. Well, other than to use a different syntax.**

I don't think that actually helps.  If you have the object already, then making 
an FCC from it already works:

https://3v4l.org/GTAGR

If you do not have the object already, then we run back into the issue I 
pointed out before where we need to differentiate a bindable from needs-binding 
callable, which is already an issue (though one I've not run into).  I think 
that's a prerequisite for adding any dedicated syntax for "make a closure that 
doesn't work until it gets bound".

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to