On Tue, Mar 14, 2023, at 3:41 PM, Rowan Tommins 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;
>          }
>      };
> }
>
> The outer variable would be captured by value, and carried around with 
> the instance, like existing closures.
>
> I suggest it is also treated as readonly, and visible strictly in the 
> lexical definition, not generally in private scope (it couldn't be 
> referenced from an applied trait, for instance).
>
> Using it to initialise a property or local variable would allow you to 
> give it an explicit scope, while still avoiding the constructor:
>
> function foo(int $outer) {
>      private $inner = $!outer;
>      return new class {
>          public function getIt() {
>              $this->inner++;
>              return $this->inner;
>          }
>      };
> }
>
>
> It then occurred to me that the same syntax could be used in 
> multi-statement anonymous functions instead of an explicit use() 
> statement. This strikes a different balance between conciseness and 
> explicitness than full automatic capture:
>
> $before = function($x) use ($y, $z) {
>      $a = $x * $y;
>      return do_something($a, $z);
> }
> $after = function($x) {
>      $a = $x * $^y;
>      return do_something($a, $^z);
> }
>
>
> To keep this message short, I've put some more examples and thoughts 
> into a GitHub Gist here: 
> https://gist.github.com/IMSoP/4157af05c79b3df4c4853f5a58766341
>
> I'd be interested to hear anyone's thoughts - is this a promising idea 
> to explore, or have I gone completely off the rails?

Pourque no los dos?

Ilija's point about implementation challenges concerns me, but my initial 
thought is that I quite like it.  I've run into the same issue with capturing 
into anon classes and wished for something like this.

As you were describing it, I was also thinking of the potential implications 
for closures, too.  That sounds... kinda fun. :-)  However, I agree with Ilija 
that the original proposal to just do it automatically would be better; and if 
that didn't pass, I have no expectation that an alternate with a funky new 
syntax would do any better.

The other concern is that this introduces a whole new realm of possible 
behaviors; like, what does $^foo mean in a non-anon-class context?  Does it?  
Could it be made to mean something in the future?  Does it become an alternate 
syntax for `global`?  What else could we do with it?  This rabbit hole goes 
very deep very quickly, and pursuing this for anon classes without considering 
the longer-term implications seems both impossible (because people will ask) 
and unwise.

--Larry Garfield

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

Reply via email to