Re: [PHP-DEV] Proposal For Return-If / Early Return / Guard Clause Syntax

This is only part of a thread. view whole thread
  110112
May 10, 2020 18:47 nikita.ppv@gmail.com (Nikita Popov)
On Sun, May 10, 2020 at 5:49 PM Ralph Schindler <ralph@ralphschindler.com>
wrote:

> Hi! > > > # Intro > > I am proposing what is a near completely syntactical addition (only > change is to language.y) to the language. The best terminology for this > syntax is are: `return if`, "return early", or "guard clauses". > > see: https://en.wikipedia.org/wiki/Guard_(computer_science) > > Over the past few years, I've seen a growing number of blog posts, > conference talks, and even tooling (for example code complexity > scoring), that suggest writing guard clauses is a good practice to > utilize. I've also seen it more prevalent in code, and even attempts at > achieving this with Exceptions (in an HTTP context) in a framework like > Laravel. > > see abort_if/throw_if: > https://laravel.com/docs/7.x/helpers#method-abort-if > > It is also worth mentioning that Ruby has similar features, and I > believe they are heavily utilized: > > see: > https://github.com/rubocop-hq/ruby-style-guide#no-nested-conditionals > > > # Proposal > > In an effort to make it a first class feature of the language, and to > make the control flow / guard clauses more visible when scanning code, I > am proposing this in the syntax of adding `return if`. > > The chosen syntax is: > > return if ( if_expr ) [: optional_return_expression] ; > > As a contrived example: > > function divide($dividend, $divisor = null) { > return if ($divisor === null || $divisor === 0); > > return $dividend / $divisor; > } > > There is already a little discussion around the choice of order in the > above statement, the main take-aways and (my) perceived benefits are: > > - it keeps the intent nearest the left rail of the code (in > normal/common-ish coding standards) > > - it treats "return if" as a meta-keyword; if must follow return for > the statement to be a guard clause. This also allows a person to more > easily discern "returns" from "return ifs" more easily since there is > not an arbitrary amount of code between them (for example if the return > expression were after return but before if). > > - it has the quality that optional parts are towards the end > > - is also has the quality that the : return_expression; is very > symmetrical to the way we demarcate the return type in method signatures > "): return type {" for example. > > - has the quality of promoting single-line conditional returns > > > # Finally > > One might say this is unnecessary syntactic sugar, which is definitely > arguable. But we do have multiple ways of achieving this. > > Of course all of these things should be discussed, I think sub-votes > (should this PR make it that far) could be considered. > > The PR is located here: > > https://github.com/php/php-src/pull/5552 > > As mentioned, some discussion is happening there as well. > > > Thanks! > Ralph Schindler > > > PS: since implementing the ::class feature 8 years ago, the addition of > the AST abstraction made this kind of syntactical change > proof-of-concept so much easier, bravo! >
This proposal looks way too specific to me. I'm a big fan of returning early -- but also of throwing early, breaking early and continuing early. Supporting this just for returns seems odd / inconsistent to me. That said, I don't think this syntax solves a real problem in the first place. If it solves a problem, it's mostly a problem of PHP coding styles being a bit overzealous when it comes to formatting requirements for early return/break/continue/throw. And that's not a problem that needs solving at the language level... Regards, Nikita
  110113
May 10, 2020 18:56 david.proweb@gmail.com (David Rodrigues)
Suggestion:

return if $x > 1; (to return "void")
return $y if ($x > 1 && $x < 5);
break if $x > 1;
break 2 if $x > 1;
throw new Exception if $x > 1;



Em dom, 10 de mai de 2020 15:48, Nikita Popov ppv@gmail.com>
escreveu:

> On Sun, May 10, 2020 at 5:49 PM Ralph Schindler <ralph@ralphschindler.com> > wrote: > > > Hi! > > > > > > # Intro > > > > I am proposing what is a near completely syntactical addition (only > > change is to language.y) to the language. The best terminology for this > > syntax is are: `return if`, "return early", or "guard clauses". > > > > see: https://en.wikipedia.org/wiki/Guard_(computer_science) > > > > Over the past few years, I've seen a growing number of blog posts, > > conference talks, and even tooling (for example code complexity > > scoring), that suggest writing guard clauses is a good practice to > > utilize. I've also seen it more prevalent in code, and even attempts at > > achieving this with Exceptions (in an HTTP context) in a framework like > > Laravel. > > > > see abort_if/throw_if: > > https://laravel.com/docs/7.x/helpers#method-abort-if > > > > It is also worth mentioning that Ruby has similar features, and I > > believe they are heavily utilized: > > > > see: > > https://github.com/rubocop-hq/ruby-style-guide#no-nested-conditionals > > > > > > # Proposal > > > > In an effort to make it a first class feature of the language, and to > > make the control flow / guard clauses more visible when scanning code, I > > am proposing this in the syntax of adding `return if`. > > > > The chosen syntax is: > > > > return if ( if_expr ) [: optional_return_expression] ; > > > > As a contrived example: > > > > function divide($dividend, $divisor = null) { > > return if ($divisor === null || $divisor === 0); > > > > return $dividend / $divisor; > > } > > > > There is already a little discussion around the choice of order in the > > above statement, the main take-aways and (my) perceived benefits are: > > > > - it keeps the intent nearest the left rail of the code (in > > normal/common-ish coding standards) > > > > - it treats "return if" as a meta-keyword; if must follow return for > > the statement to be a guard clause. This also allows a person to more > > easily discern "returns" from "return ifs" more easily since there is > > not an arbitrary amount of code between them (for example if the return > > expression were after return but before if). > > > > - it has the quality that optional parts are towards the end > > > > - is also has the quality that the : return_expression; is very > > symmetrical to the way we demarcate the return type in method signatures > > "): return type {" for example. > > > > - has the quality of promoting single-line conditional returns > > > > > > # Finally > > > > One might say this is unnecessary syntactic sugar, which is definitely > > arguable. But we do have multiple ways of achieving this. > > > > Of course all of these things should be discussed, I think sub-votes > > (should this PR make it that far) could be considered. > > > > The PR is located here: > > > > https://github.com/php/php-src/pull/5552 > > > > As mentioned, some discussion is happening there as well. > > > > > > Thanks! > > Ralph Schindler > > > > > > PS: since implementing the ::class feature 8 years ago, the addition of > > the AST abstraction made this kind of syntactical change > > proof-of-concept so much easier, bravo! > > > > This proposal looks way too specific to me. I'm a big fan of returning > early -- but also of throwing early, breaking early and continuing early. > Supporting this just for returns seems odd / inconsistent to me. > > That said, I don't think this syntax solves a real problem in the first > place. If it solves a problem, it's mostly a problem of PHP coding styles > being a bit overzealous when it comes to formatting requirements for early > return/break/continue/throw. And that's not a problem that needs solving at > the language level... > > Regards, > Nikita >
  110116
May 10, 2020 19:59 ralph@ralphschindler.com (Ralph Schindler)
On 5/10/20 1:56 PM, David Rodrigues wrote:
> Suggestion: > > return if $x > 1; (to return "void") > return $y if ($x > 1 && $x < 5); > break if $x > 1; > break 2 if $x > 1; > throw new Exception if $x > 1; >
100% that will/should be a votable alternative option should this get to the voting phase. I have reasons for why I chose my initial path, but its worth mentioning I favor the optional value at the end maybe 65% to 35% where the value is after the initial keyword. Thanks for taking the time! -ralph schindler
  110119
May 10, 2020 21:33 david.proweb@gmail.com (David Rodrigues)
I just think that this way is more compatible witth the reading. "Return X
if Y" seems better than "return (if) X: (then) Y". Too the ":" could
conflicts with return type.

Em dom, 10 de mai de 2020 16:59, Ralph Schindler <ralph@ralphschindler.com>
escreveu:

> > > On 5/10/20 1:56 PM, David Rodrigues wrote: > > Suggestion: > > > > return if $x > 1; (to return "void") > > return $y if ($x > 1 && $x < 5); > > break if $x > 1; > > break 2 if $x > 1; > > throw new Exception if $x > 1; > > > > 100% that will/should be a votable alternative option should this get to > the voting phase. > > I have reasons for why I chose my initial path, but its worth mentioning > I favor the optional value at the end maybe 65% to 35% where the value > is after the initial keyword. > > Thanks for taking the time! > -ralph schindler >
  110115
May 10, 2020 19:50 ralph@ralphschindler.com (Ralph Schindler)
> This proposal looks way too specific to me. I'm a big fan of returning > early -- but also of throwing early, breaking early and continuing > early. Supporting this just for returns seems odd / inconsistent to me.
I agree with this sentiment, and I'll update the PR accordingly and this will be reflected when I make the RFC itself. (Throw feels different as its parameter is not optional and is always a complex type, and is in a different area of the parser... But I'll look more deeply at adding that soon.)
> That said, I don't think this syntax solves a real problem in the first > place. If it solves a problem, it's mostly a problem of PHP coding > styles being a bit overzealous when it comes to formatting requirements > for early return/break/continue/throw. And that's not a problem that > needs solving at the language level...
I think we could say the same thing about most new additions: fn arrow functions, str_starts_with/str_ends_with, trailing comma in lists & function calls, str_contains(), flexible (indented) heredocs, list reference assignment, native de-structuring.. just to name a few that all fit into the same kind of quality of life category. Nearly all of those were achievable via some kind of syntax before their addition, but I think we can agree we're better off having them, than not- even if one chooses not to use them. Having been programming with PHP for 22+ years now, and making it a point to evolve my tastes/preferences with the changing language and whatever the prevalent practices are in the community (and other languages), my desire for including these quality of life improvements remains quite high as it keeps the language interesting and competitive. Put another way, as someone who's come to really appreciate the aesthetics and clarity of intent of code,.. and having seen this is some places in the wild already I feel are successful, I personally feel its a good thing to perhaps to run through the RFC process for inclusion in 8. Thanks! Ralph Schindler