Hey Rowan

On Tue, Mar 14, 2023 at 9:41 PM Rowan Tommins <rowan.coll...@gmail.com> wrote:
>
> Hi all,
>
> I have been pondering for a while how to improve the anonymous class
> syntax to allow "capturing" of values from the outer scope, and came up
> with the idea of a special variable marker for "lexically captured
> variable" - instead of $foo, you would write $!foo or $^foo (I quite
> like the "upwardness" of $^).
>
> To give a simple example, values can only pass into the anonymous class
> via its constructor, like this:
>
> function foo(int $outer) {
>      return new class($outer) {
>          public function __construct(
>              private int $myProp
>          ) {}
>          public function getIt() {
>              return $this->myProp;
>          }
>      };
> }
>
> The idea is that you would instead be able to reference an outer
> variable directly anywhere in the declaration, removing a lot of
> boilerplate:
>
> function foo(int $outer) {
>      return new class {
>          public function getIt() {
>              return $^outer;
>          }
>      };
> }

One thing to note is that, as I've learned recently, anonymous classes
can actually be instantiated at a later point with some tricks.

https://3v4l.org/2OcmP

This could be avoided by adding the value to the constructor, but that
fully defeats the purpose of your proposal. Holding the value
indefinitely would create a leak and also doesn't really work as
`createAnonymousClass` could be called multiple times and thus
capturing multiple `$value`s. We could also decide to disallow
instantiations of anonymous classes in other places, that would
probably make most sense. This way the captured value could be
attached somewhere in the object and $^foo could access that instead.

That being said, I am indeed very skeptical if the added complexity is worth it.

```
// Lexical values could be used to initialse private, protected, or
public properties
// The same lexical value can be used any number of times
$x = 1;
$example = new class {
    private $x = $^x;
    protected $sharedX = $^x;
    public $alsoX = $^x;
}
```

This could also prove technically challenging. Currently, property
defaults are constant ASTs and unique per class (not object). For your
case, they would need to be different per instance, which might
require quite a bit of refactoring.

As for the syntax in closures, that seems a bit more useful to me
personally, although I dislike the multi-nesting. Moving code, it
might be easy to miss that the number of "^" needs adjustments. I'd
personally prefer the previously proposed approach of capturing just
by name. Good naming should minimize the risk of clashing variables.

Regards,
Ilija

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

Reply via email to