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

This is only part of a thread. view whole thread
  110196
May 17, 2020 04:33 sarkedev@gmail.com (Peter Stalman)
A few thoughts:


1. I agree with the sentiment that this syntactic sugar doesn't
actually save any verbosity, so it's not really syntactic sugar at
all.


2. There appears to now be another RFC by Pavel Patapau, specifically
focused on a Guard statement as a new keyword
(https://wiki.php.net/rfc/guard_statement), which now has its separate
discussion.


3. As Thomas Lamy mentioned, I too would prefer a single keyword.
Consider the following two examples:

    function foo($bar)
    {
        if ($bar === 1)
            return;

        if ($bar === 666)
            delete_everything();
    }

    function foo($bar)
    {
        if ($bar === 1)
            return

        if ($bar === 666);
            delete_everything();
    }

Both would now be valid syntax, and IDEs would have a harder time
warning about the misplaced semicolon in the second example.  Wouldn't
be very common, but still.


4. However, this RFC is interesting to me because there be a way to
modify it to allow for less verbose refactoring, and kinda allowing
returns to bubble up like exceptions do.  I think it would only make
sense if it's a "if not null then return" type of thing.

Consider the following (a bit contrived, but I hope you get the point):

    function main_function()
    {
        $result = calculate($var);
        if ($result !== null)
            return $result;

        /* do other important stuff */
    }

    function main_function()
    {
        ifnotnullreturn calculate($var);

        /* do other important stuff */
    }

Obviously not an ideal keyword, but this is the only thing I can think
of where this type of syntactic sugar makes sense and decreases
verbosity.  Something similar can also be accomplished with exception
though.


5. Finally, I think if we start putting several returns at the same
indentation then the cognitive load increases because we can no longer
tell if a return is actually a return at a glance.


Thanks,
Peter

On Fri, May 15, 2020 at 11:58 AM Victor Bolshov <crocodile2u@gmail.com> wrote:
> > Hi internals, > > I think it's just as good to write: > if ($condition) return $retval; > Yes, there are subtle semantic differences the new syntax would emphasize, but it doesn't feel like it justifies it. New syntax also means the need to support it, for IDEs and other tools, static analysis tools, code-style tools - and all that for a very tiny benefit, if any. > Cheers, > Victor > > Sent from Mailspring (https://link.getmailspring.com/link/85C8412B-B04A-4853-8C4C-E270FCB35EEE@getmailspring.com/0?redirect=https%3A%2F%2Fgetmailspring.com%2F&recipient=aW50ZXJuYWxzQGxpc3RzLnBocC5uZXQ%3D), the best free email app for work > On 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 clause > s 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! -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php >
May 19, 2020 06:53 php@manuelcanga.dev (Manuel Canga)
Hi, Internals,



 ---- En dom, 17 may 2020 06:33:51 +0200 Peter Stalman <sarkedev@gmail.com> escribió ----
 > A few thoughts:
 > 
 > 
 > 1. I agree with the sentiment that this syntactic sugar doesn't
 > actually save any verbosity, so it's not really syntactic sugar at
 > all.
 > 
 > 
 > 2. There appears to now be another RFC by Pavel Patapau, specifically
 > focused on a Guard statement as a new keyword
 > (https://wiki.php.net/rfc/guard_statement), which now has its separate
 > discussion.
 > 
 > 
 > 3. As Thomas Lamy mentioned, I too would prefer a single keyword.
 > Consider the following two examples:
 > 
 >     function foo($bar)
 >     {
 >         if ($bar === 1)
 >             return;
 > 
 >         if ($bar === 666)
 >             delete_everything();
 >     }
 > 
 >     function foo($bar)
 >     {
 >         if ($bar === 1)
 >             return
 > 
 >         if ($bar === 666);
 >             delete_everything();
 >     }
 > 
 > Both would now be valid syntax, and IDEs would have a harder time
 > warning about the misplaced semicolon in the second example.  Wouldn't
 > be very common, but still.
 > 
 > 
 > 4. However, this RFC is interesting to me because there be a way to
 > modify it to allow for less verbose refactoring, and kinda allowing
 > returns to bubble up like exceptions do.  I think it would only make
 > sense if it's a "if not null then return" type of thing.
 > 
 > Consider the following (a bit contrived, but I hope you get the point):
 > 
 >     function main_function()
 >     {
 >         $result = calculate($var);
 >         if ($result !== null)
 >             return $result;
 > 
 >         /* do other important stuff */
 >     }
 > 
 >     function main_function()
 >     {
 >         ifnotnullreturn calculate($var);
 > 
 >         /* do other important stuff */
 >     }
 > 
 > Obviously not an ideal keyword, but this is the only thing I can think
 > of where this type of syntactic sugar makes sense and decreases
 > verbosity.  Something similar can also be accomplished with exception
 > though.
 > 
 > 
 > 5. Finally, I think if we start putting several returns at the same
 > indentation then the cognitive load increases because we can no longer
 > tell if a return is actually a return at a glance.
 > 
 > 
 > Thanks,
 > Peter
 > 

I agree. 

¿ Maybe something like...

   function main_function()
     {
         escape when(  calculate($var) );

         /* do other important stuff */
    }


`escape when( expr )`  returns value of  `expr`  to caller function  when `expr` evaluate to true otherwise next line.

   function main_function()
     {
         escape with $ a + 1  when(  !calculate($var)  );

         /* do other important stuff */
    }


`escape with expr1 when( expr2 )`  returns value of `expr1` to caller function  when `expr2` evaluate to true otherwise next line.



Regards
--
Manuel Canga
  110211
May 19, 2020 07:04 php@manuelcanga.dev (Manuel Canga)
---- En mar, 19 may 2020 08:53:46 +0200 Manuel Canga <php@manuelcanga.dev> escribió ----
 > 
 > Hi, Internals,
 > 
 > 
 > 
 >  ---- En dom, 17 may 2020 06:33:51 +0200 Peter Stalman <sarkedev@gmail.com> escribió ----
 >  > A few thoughts:
 >  > 
 >  > 
 >  > 1. I agree with the sentiment that this syntactic sugar doesn't
 >  > actually save any verbosity, so it's not really syntactic sugar at
 >  > all.
 >  > 
 >  > 
 >  > 2. There appears to now be another RFC by Pavel Patapau, specifically
 >  > focused on a Guard statement as a new keyword
 >  > (https://wiki.php.net/rfc/guard_statement), which now has its separate
 >  > discussion.
 >  > 
 >  > 
 >  > 3. As Thomas Lamy mentioned, I too would prefer a single keyword.
 >  > Consider the following two examples:
 >  > 
 >  >     function foo($bar)
 >  >     {
 >  >         if ($bar === 1)
 >  >             return;
 >  > 
 >  >         if ($bar === 666)
 >  >             delete_everything();
 >  >     }
 >  > 


 >  > 
 >  > Both would now be valid syntax, and IDEs would have a harder time
 >  > warning about the misplaced semicolon in the second example.  Wouldn't
 >  > be very common, but still.
 >  > 
 >  > 
 >  > 4. However, this RFC is interesting to me because there be a way to
 >  > modify it to allow for less verbose refactoring, and kinda allowing
 >  > returns to bubble up like exceptions do.  I think it would only make
 >  > sense if it's a "if not null then return" type of thing.
 >  > 
 >  > Consider the following (a bit contrived, but I hope you get the point):
 >  > 
 >  >     function main_function()
 >  >     {
 >  >         $result = calculate($var);
 >  >         if ($result !== null)
 >  >             return $result;
 >  > 
 >  >         /* do other important stuff */
 >  >     }
 >  > 
 >  >     function main_function()
 >  >     {
 >  >         ifnotnullreturn calculate($var);
 >  > 
 >  >         /* do other important stuff */
 >  >     }
 >  > 
 >  > Obviously not an ideal keyword, but this is the only thing I can think
 >  > of where this type of syntactic sugar makes sense and decreases
 >  > verbosity.  Something similar can also be accomplished with exception
 >  > though.
 >  > 
 >  > 
 >  > 5. Finally, I think if we start putting several returns at the same
 >  > indentation then the cognitive load increases because we can no longer
 >  > tell if a return is actually a return at a glance.
 >  > 
 >  > 
 >  > Thanks,
 >  > Peter
 >  > 
 > 
 > I agree. 
 > 
 > ¿ Maybe something like...
 > 
 >    function main_function()
 >      {
 >          escape when(  calculate($var) );
 > 
 >          /* do other important stuff */
 >     }
 > 
 > 
 > `escape when( expr )`  returns value of  `expr`  to caller function  when `expr` evaluate to true otherwise next line.
 > 
 >    function main_function()
 >      {
 >          escape with $ a + 1  when(  !calculate($var)  );
 > 
 >          /* do other important stuff */
 >     }
 > 
 > 
 > `escape with expr1 when( expr2 )`  returns value of `expr1` to caller function  when `expr2` evaluate to true otherwise next line.
 > 
 > 

Upgrade version.

Maybe is better:

`escape when( expr )`  returns null  to caller function  when `expr` evaluate to true otherwise next line.

 `escape with expr1 when( expr2 )`  returns value of `expr1` to caller function  when `expr2` evaluate to true otherwise next line.

Then these code are equals to:

 >  >     function main_function()
 >  >     {
 >  >         $result = calculate($var);
 >  >         if ($result !== null)
 >  >             return $result;
 >  > 
 >  >         /* do other important stuff */
 >  >     }
 >  > 

function main_function() 
{
   escape with $result when(   $result = calculate($var) );

  /* do other important stuff */
}


 >  >     function foo($bar)
 >  >     {
 >  >         if ($bar === 1)
 >  >             return;
 >  > 
 >  >         if ($bar === 666)
 >  >             delete_everything();
 >  >     }


function foo($var) {
  escape when( $bar === 1 ||  $bar !== 600 );

  delete_everything();
}