Re: Brainstorming idea: inline syntax for lexical (captured) variables

From: Date: Tue, 14 Mar 2023 22:54:40 +0000
Subject: Re: Brainstorming idea: inline syntax for lexical (captured) variables
References: 1  Groups: php.internals 
Request: Send a blank email to internals+get-119700@lists.php.net to get a copy of this message
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

« previous php.internals (#119700) next »