Re: [RFC] Short Closures 2, aka auto-capture take 3
| From: | Nikita Popov | Date: | Thu, 09 Jun 2022 19:35:37 +0000 |
| Subject: | Re: [RFC] Short Closures 2, aka auto-capture take 3 | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-117895@lists.php.net to get a copy of this message | ||
On Thu, Jun 9, 2022 at 9:29 PM Marco Pivetta <ocramius@gmail.com> wrote:
>
> On Thu, 9 Jun 2022 at 21:27, Nikita Popov <nikita.ppv@gmail.com> wrote:
>
>> On Thu, Jun 9, 2022 at 8:15 PM Arnaud Le Blanc <arnaud.lb@gmail.com>
>> wrote:
>>
>>> Hi,
>>>
>>> On jeudi 9 juin 2022 18:46:53 CEST Marco Pivetta wrote:
>>> > ## nesting these functions within each other
>>> >
>>> > What happens when/if we nest these functions? Take this minimal
>>> example:
>>> >
>>> > ```php
>>> > $a = 'hello world';
>>> >
>>> > (fn () {
>>> > (fn () {
>>> > echo $a;
>>> > })();
>>> > })();
>>> > ```
>>>
>>> Capture bubbles up. When an inner function uses a variable, the outer
>>> function
>>> in fact uses it too, so it's captured by both functions, by-value.
>>>
>>> This example prints "hello world": The inner function captures $a from
>>> the
>>> outer function, which captures $a from its declaring scope.
>>>
>>> This is equivalent to
>>>
>>> ```php
>>> (function () use ($a) {
>>> (function () use ($a) {
>>> echo $a;
>>> })();
>>> })();
>>> ```
>>>
>>> > ## capturing
$this
>>> >
>>> > In the past (also present), I had to type static fn () =>
>>> > ... or
>>> `static
>>> > function () { ...` all over the place, to avoid implicitly binding
>>> $this
>>> > to a closure, causing hidden memory leaks.
>>> >
>>> > Assuming following:
>>> >
>>> > * these new closures could capture $this
>>> > automatically, once
>>> detected
>>> > * these new closures can optimize away unnecessary variables that
>>> aren't
>>> > captured
>>> >
>>> > Would that allow us to get rid of static fn () {
>>> > declarations, when
>>> > creating one of these closures in an instance method context?
>>>
>>> It would be great to get rid of this, but ideally this would apply to
>>> Arrow
>>> Functions and Anonymous Functions as well. This could be a separate RFC.
>>>
>>
>> I've tried this in the past, and this is not possible due to implicit
>> $this uses. See
>>
>> https://wiki.php.net/rfc/arrow_functions_v2#this_binding_and_static_arrow_functions
>> for a brief note on this. The tl;dr is that if your closure does "fn() =>
>> Foo::bar()" and Foo happens to be a parent of your current scope and bar()
>> a non-static method, then this performs a scoped instance call that
>> inherits $this. Not binding $this here would result in an Error exception,
>> but the compiler doesn't have any way to know that $this needs to be bound.
>>
>> Regards,
>> Nikita
>>
>
> Hey Nikita,
>
> Do you have another example? Calling instance methods statically is...
> well... deserving a hard crash :|
>
Maybe easier to understand if you replace Foo::bar() with parent::bar()?
That's the most common spelling for this type of call.
I agree that the syntax we use for this is unfortunate (because it is
syntactically indistinguishable from a static method call, which it is
*not*), but that's what we have right now, and we can hardly just stop
supporting it.
Regards,
Nikita