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

From: Date: Thu, 16 Mar 2023 23:05:35 +0000
Subject: Re: Brainstorming idea: inline syntax for lexical (captured) variables
References: 1 2 3 4 5 6  Groups: php.internals 
Request: Send a blank email to internals+get-119732@lists.php.net to get a copy of this message
On 16/03/2023 22:14, Larry Garfield wrote:
Wouldn't the functionality described boil down to essentially just materializing into a few extra lines in the constructor? At least to my ignorant non-engine brain it seems straightforward to have this: $a = 1; $b = 2; $c = 3; $o = new class ($a, $b) use ($c) { public function __construct(private int $a, private int $b) {} public function something() {} } Desugar to this: $c = class ($a, $b) use ($c) { private $c; public function __construct(private int $a, private int $b) {
     $this->c = 3;  // By value only, so this should be fine?
} public function something() {} }
Not quite - as Ilija pointed out, the class definition gets compiled once, but the capture needs to happen for every instance, with (potentially) different values of $c. In other words, $c needs to be injected as a constructor argument, not a constant in the class definition. That's still fine, in principle - you can compile to this: $o = class ($a, $b, $c) { public function __construct(private int $a, private int $b, private $c) { } public function something() {} } Or once constructor promotion is de-sugared as well, this: $o = class ($a, $b, $c) { private int $a; private int $b; private $c; public function __construct($a, $b, $c) {
     $this->a = $a; // from constructor promotion
     $this->b = $b; // from constructor promotion
     $this->c = $c; // from use() statement
     // other lines from body of constructor go here
} public function something() {} } It just introduces a lot of extra cases to handle: * If there's no constructor, create one * If there is a constructor with other arguments, merge the argument lists; since there will then be an explicit argument list to "new class()", merge those lists as well * Maybe different handling if those other arguments are already using constructor promotion, as in this example * If there are existing lines in the constructor body, combine those with the auto-generated assignments Which is why I'm thinking a first implementation would be reasonable which just took this approach: * "new class" can either have an argument list or a use() statement, not both * the use() statement generates a constructor at the top of the class * if the class body already contains a constructor, the compiler will complain that you have two methods named "__construct" Regards, -- Rowan Tommins [IMSoP]

« previous php.internals (#119732) next »