[RFC] Alternative "use" syntax for Closures

php.internals

Net Mo

7 years ago
Hello PHP, I just published https://wiki.php.net/rfc/alternative-closure-use-syntax I would love your opinion on this I know it seems overkill and wrong to have two different syntaxes for the same thing, but I really believe that's all we need to fix one of the most hated PHP syntax bits. Thank you. Wes

Marco Pivetta

7 years ago
Hey Wes, On Sat, Jun 15, 2019, 23:53 Wes <netmo.php@gmail.com> wrote:
> Hello PHP, I just published > > https://wiki.php.net/rfc/alternative-closure-use-syntax > > I would love your opinion on this > > I know it seems overkill and wrong to have two different syntaxes for the > same thing, but I really believe that's all we need to fix one of the most > hated PHP syntax bits. > > Thank you. > > Wes >
Tbh, I love the fact that closures have explicitly imported scope: makes it clear when something is starting to have too many responsibilities.

Girgias

7 years ago
On Sat, 15 Jun 2019 at 23:57, Marco Pivetta <ocramius@gmail.com> wrote:
> On Sat, Jun 15, 2019, 23:53 Wes <netmo.php@gmail.com> wrote: > > > Hello PHP, I just published > > > > https://wiki.php.net/rfc/alternative-closure-use-syntax > > > > I would love your opinion on this > > > > I know it seems overkill and wrong to have two different syntaxes for the > > same thing, but I really believe that's all we need to fix one of the > most > > hated PHP syntax bits. > > > > Thank you. > > > > Wes > > > > Tbh, I love the fact that closures have explicitly imported scope: makes it > clear when something is starting to have too many responsibilities. >
I personally don't really mind the current way of doing imports and I agree with Marco that it makes clean when a closure tries to do too much. However, I kind of like/understand the syntax proposed so this is more a +0 for me than anything else. Best regards George P. Banyard

Net Mo

7 years ago
Declaring variables or specifying which ones to import. Essentially it's the same thing, so what gives? It's PHP's syntax, IMHO, that makes the thing irritating to write :D

Marco Pivetta

7 years ago
On Sun, Jun 16, 2019, 00:09 Wes <netmo.php@gmail.com> wrote:
> Declaring variables or specifying which ones to import. Essentially it's > the same thing, so what gives? It's PHP's syntax, IMHO, that makes the > thing irritating to write :D >
Just more AST to process, if you ask me 😐

Kalle Sommer Nielsen

7 years ago
Den søn. 16. jun. 2019 kl. 01.09 skrev Wes <netmo.php@gmail.com>:
> > Declaring variables or specifying which ones to import. Essentially it's > the same thing, so what gives? It's PHP's syntax, IMHO, that makes the > thing irritating to write :D
The proposed syntax was also that of the proposed syntax when closures arrived in 5.3 (and back then it was using the then keyword 'lexical'), anyway. I believe the current syntax was chosen due to scopes, as values are bound specifically when the closure is created and not when the closure is executed. For example if you have a function that returns a closure and the closure imports a variable local to that and then later call it from a different scope, that means we need to keep that old scope alive until then which can be rather problematic, instead it was decided back then to have the import of parent scope variables as apart of the prototype as it is possible to capture the value in the Engine at this point in time. I agree its odd but I would much rather keep the current implementation. Also in regards to the RFC, if you have massive argument lists like in the RFC then I think you should re-think your design and put such complex computations into separate methods which also encourages better testability.
-- regards, Kalle Sommer Nielsen kalle@php.net

Net Mo

7 years ago
Hi Kalle, I realize it's going to be a bit odd when binding by value. But it's not that hard to grasp. ``` $a = 123; $closure = function(){ use $a; echo $a; // 123 }; $a = 345; ``` For this reason I specified it is mandatory to have `use` only at the very top (otherwise, it would _really_ be confusing :P)

Kalle Sommer Nielsen

7 years ago
Hi Den søn. 16. jun. 2019 kl. 01.37 skrev Wes <netmo.php@gmail.com>:
> > Hi Kalle, I realize it's going to be a bit odd when binding by value. But > it's not that hard to grasp. > > ``` > $a = 123; > $closure = function(){ > use $a; > echo $a; // 123 > }; > $a = 345; > ```
Take this example: function get_closure() { $a = 123; return function() { use $a; echo $a; }; } get_closure()(); $a is not available at this time because the scope of which $a exists in is destroyed at this point, which is why it exists as apart of the prototype like I mentioned and therefore it can be captured. Your idea means we need to scan the body of the declared closure for use statements to perform the binding at this stage, adding extra specialized steps in the executor for only makes me question the motive for this again, and if the motive is that "I'm passing an excessive amount of values to a closure", then I think you are forcing a technique that isn't mean for this to do it anyway. Another thing to take into consideration here is the performance impact that it can potentially have. Whether or not its at the top of the body or separated in multiple statements or all over the body still means we need to check if the body contains such a statement and do the right computations for it, I still don't think the argument presented in the RFC justifies this potential cost, and would like to see a demo implementation and impact it would have first.
-- regards, Kalle Sommer Nielsen kalle@php.net

M. W. Moe

7 years ago
Hello, mostly, your argument in your rfc, is all about not finding a good syntax; hence your have a terrible coding style and you want to change the language for that. ``` $fn = function ( T1 $arg1_ , T1 $arg2_ , T1 $arg3_ , T1 $arg4_ , T1 $arg5_ , T1 $arg6_ ) use ($var1, &$var2, &$var3, &$var4): T2 { // If you want to import more scope vars your code is // smelly, should think about writing something else. return new T2; }; ``` On Sat, Jun 15, 2019 at 3:52 PM Kalle Sommer Nielsen <kalle@php.net> wrote:

Net Mo

7 years ago
Welcome to the first inevitable patronizing message... No, my code is not smelly. If something is smelling for you, check your armpits. Importing 4 variables is not rare. If you think it's rare and should be done differently, maybe you should first actually do something with Closures before telling people they are wrong. And if you use actual names instead of "$var1" or "T1" you will see why I am proposing to move the lexical imports where they are the least invasive.

M. W. Moe

7 years ago
Hello, if you are upset; it's not the place here; your argument is efficiently based on problems of indentation and handling commas properly. Moreover, but not least, you have no idea what a lambda is; if we admit it what you propose; that is not feasible in PHP; why? because it would require a preprocessor; in the case presented, it would be necessary to import all that existing scope then making a selection; nobody wants that to happen. If you do not accept any rational criticism; you should think of doing something else; I do not know; gardening maybe? who knows. P.S For my use of the "closure" you made a fool yourself beyond what you can grasp; but anyhow, my dear, it's refreshing, you made smile. On Sat, Jun 15, 2019 at 4:34 PM Wes <netmo.php@gmail.com> wrote:

Mark Clements (HappyDog)

7 years ago
""M. W. Moe"" <mo.mu.wss@gmail.com> wrote in message news:CAHN63oOGX1E8n2_N7-m=vhYTf7kXccPvLW3LOkroTNZUzz-wxw@mail.gmail.com...
> If you do not accept any rational criticism; you should think of doing > something else; I do not know; gardening maybe? who knows. > > P.S For my use of the "closure" you made a fool yourself beyond what you > can grasp; but anyhow, my dear, it's refreshing, you made smile.
Please try and keep it civil. That was uncalled for. - Mark Clements (HappyDog)

Nikita Popov

7 years ago
On Sun, Jun 16, 2019 at 3:02 AM M. W. Moe <mo.mu.wss@gmail.com> wrote:
> Hello, > > if you are upset; it's not the place here; your argument is efficiently > based on problems of indentation and handling commas > properly. > > Moreover, but not least, you have no idea what a lambda is; if we admit it > what you propose; that is not feasible in PHP; why? because it would > require a preprocessor; in the case presented, it would be necessary to > import all that existing scope then making a selection; nobody wants that > to happen. > > If you do not accept any rational criticism; you should think of doing > something else; I do not know; gardening maybe? who knows. > > P.S For my use of the "closure" you made a fool yourself beyond what you > can grasp; but anyhow, my dear, it's refreshing, you made smile. >
Please keep discussion constructive and refrain from ad hominems. If this happens again, you will be removed from this mailing list. Nikita

Net Mo

7 years ago
Hi Kalle. I hope it's feasible. Unfortunately I don't know much about internals. Any info on the matter would be very appreciated, though :P Anyway, if we can scan the function body to complain about `return null;` when the function is `:void`, surely we can scan just the very top of the function body to read the imports :P

Kalle Sommer Nielsen

7 years ago
Den søn. 16. jun. 2019 kl. 02.48 skrev Wes <netmo.php@gmail.com>:
> > Hi Kalle. I hope it's feasible. Unfortunately I don't know much about > internals. Any info on the matter would be very appreciated, though :P > > Anyway, if we can scan the function body to complain about `return null;` > when the function is `:void`, surely we can scan just the very top of the > function body to read the imports :P
The latter is detected at a different stage, we can detect some type errors during the language parser phase, for your example if the prototype of the function/method has a return type set to void, then any return statements within the body causes an error, while most other errors happens at runtime: function invalid() : string { return null; } Will first throw an error the moment it is called, not when it is parsed unlike your example. The problem here is that you cannot perform that binding of a variable until the runtime kicks in (you don't know if $a exists until you attempt at binding it which must be at the time the closure is created, not when executed from an engine perspective). (Also, regarding the other email you sent to Moe, please keep this language and such comments off the list and in private, such does not belong to internals, it is a mailing list about the development of a programming language, not a kinder garden)
-- regards, Kalle Sommer Nielsen kalle@php.net

Rowan Collins

7 years ago
On Sat, 15 Jun 2019 at 23:22, Kalle Sommer Nielsen <kalle@php.net> wrote:
> The proposed syntax was also that of the proposed syntax when closures > arrived in 5.3 (and back then it was using the then keyword > 'lexical'), anyway. I believe the current syntax was chosen due to > scopes, as values are bound specifically when the closure is created > and not when the closure is executed. >
Hi Kalle, Thanks for the background info, I've often wondered why the syntax isn't more similar to "global" and "static" declarations. It hadn't occurred to me before that the function signature can be processed without inspecting the function body. While I think the proposed syntax has its upsides, I agree with others that adding it as an alternative at this stage doesn't add very much. People who don't like explicit imports still won't like it, and people who are used to the existing syntax will write style guides prohibiting the new. When I suggested on SO chat that a long list of imports was a similarly bad sign as a long list of parameters, I was scoffed at, so I would be interested to see examples where large numbers of imports are justified. Assuming there are such use cases, it seems like automatic capture will be a better solution. I'm not personally keen on extending the arrow syntax with a full body - "fn()=>{}" is barely shorter than "function(){}", and I think "arrow functions are for short expressions" is a useful distinction and constraint. If we really need automatic capture, I'd prefer for it to be opted into in the normal syntax, e.g. "function() use(*) { ... }". We could even have "use(&*)" for "automatic capture by reference", if we wanted to go that far. Regards,
-- Rowan Collins [IMSoP]

Alexandru Pătrănescu

7 years ago
Hi, If at some point we would have multi-statement body arrow function, I would assume that one option would be to have the closure done automatically, as it is done now on the one-line arrow function. If the values will not be implicitly captured, maybe a new syntax to capture can be designed there, for multi-line arrow functions. A way to scan variables is already implemented for the one-line and, I guess, a way to scan for few lines could also be implemented easier for the new syntax. Alex On Sun, Jun 16, 2019, 00:54 Wes <netmo.php@gmail.com> wrote:

Net Mo

7 years ago
Hi Alexandru, I don't think there is intention to do that. In particular with pass by reference. Importing variables by-ref likely will be explicit, given recent discussions on the matter. The new Closures or the old ones might automatically "copy" all variables (by-value) at some point, but I doubt they will ever "inherit" variables automatically (by-reference). Hence the proposed syntax or some other one will be needed for that. e.g.: ``` $foo = 123; $fn1 = fn() => { echo $foo; // auto import by value }; $fn2 = fn() => { use &$foo; // import by ref echo $foo; }; $foo = 456; $fn1(); // 123 $fn2(); // 456 ```

Mark Randall

7 years ago
On 15/06/2019 22:53, Wes wrote:
> Hello PHP, I just published > https://wiki.php.net/rfc/alternative-closure-use-syntax > I would love your opinion on this
I'm not overly fond of it myself because I think it could make it slightly more difficult to parse in my brain. If there was a: $x = 0; $y = 1; $closure = function() use (...) { }; Where "use (...)" would auto-capture all of the used variables in a similar manner to short closures, that would certainly save a bit of time.
-- Mark Randall

Markus Fischer

7 years ago
Hi, On 15.06.19 23:53, Wes wrote:
> https://wiki.php.net/rfc/alternative-closure-use-syntax >
Thanks for the RFC and effort,
> I know it seems overkill and wrong to have two different syntaxes for the > same thing, but I really believe that's all we need to fix one of the most > hated PHP syntax bits.
Technically, no versions seems better than the other. Personally I don't see how this fixes anything but introduces two ways of doing the same thing. I've never really seen people having problems with the current syntax but I'm not saying there aren't. The same argument can be made for all the array/str function and people having a hard time to remember which function takes theneedle/haystack and what argument position or similar to map/reduce/etc. From the RFC:
> Specifically, it requires a lot of effort to write compared to normal
expressions. This are bold words: "a lot". The problem with this argument is that there's almost no way to properly argue for or against this. This is like art and creativity: it's a personal choice and some like it, some not. Choice is nice and all, but in terms of code style it just creates an overhead (= decision to make which style to use) and I rather prefer "one true" way of doing things unless absolute necessary. I'm -1 on introducing a 2nd syntax without clear benefits of any kind that I can see. That syntax exists now for 10 years, I'd say people can and do accommodate and there's no need for this. thanks, - Markus