Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:110109 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 97793 invoked from network); 10 May 2020 17:50:21 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 10 May 2020 17:50:21 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 2666E1804DD for ; Sun, 10 May 2020 09:26:34 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RDNS_NONE,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS701 96.241.0.0/16 X-Spam-Virus: No X-Envelope-From: Received: from nebula.zort.net (unknown [96.241.205.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 10 May 2020 09:26:33 -0700 (PDT) Received: from [10.0.1.2] (pulsar.zort.net [96.241.205.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by nebula.zort.net (Postfix) with ESMTPSA id 69EDE2005BBBF; Sun, 10 May 2020 12:26:32 -0400 (EDT) DKIM-Filter: OpenDKIM Filter v2.11.0 nebula.zort.net 69EDE2005BBBF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zort.net; s=zort; t=1589127992; bh=zMQID1qD4EdZRpyIYWNrQ81BspVpjRNBrnF/nXWACR8=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=r+FvBwuT9dyWbhGD32+dxq2VqcvUmthB9TJeQSIRtlMgns5SvJsvbhCIdGuXwaSdk FEkPeOtDzrpE7DWSoxRHHBhAermSVDgb3WZEq2XeEG1JoAdTIZlhpbiLIpNKq2wVyG D7kdvg/HJk+bA9APsiOlQC1LTWXRD7zhsYptmxCs= Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.80.23.2.2\)) In-Reply-To: Date: Sun, 10 May 2020 12:26:32 -0400 Cc: PHP internals Content-Transfer-Encoding: quoted-printable Message-ID: References: To: Ralph Schindler X-Mailer: Apple Mail (2.3608.80.23.2.2) Subject: Re: [PHP-DEV] Proposal For Return-If / Early Return / Guard Clause Syntax From: jbafford@zort.net (John Bafford) Hi Ralph, > On May 10, 2020, at 11:49, Ralph Schindler = wrote: >=20 > Hi! >=20 >=20 > # Intro >=20 > 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". >=20 > see: https://en.wikipedia.org/wiki/Guard_(computer_science) >=20 > 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. >=20 > see abort_if/throw_if: = https://laravel.com/docs/7.x/helpers#method-abort-if >=20 > It is also worth mentioning that Ruby has similar features, and I = believe they are heavily utilized: >=20 > see: = https://github.com/rubocop-hq/ruby-style-guide#no-nested-conditionals >=20 >=20 > # Proposal >=20 > 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`. >=20 > The chosen syntax is: >=20 > return if ( if_expr ) [: optional_return_expression] ; >=20 > As a contrived example: >=20 > function divide($dividend, $divisor =3D null) { > return if ($divisor =3D=3D=3D null || $divisor =3D=3D=3D 0); >=20 > return $dividend / $divisor; > } >=20 > There is already a little discussion around the choice of order in the = above statement, the main take-aways and (my) perceived benefits are: >=20 > - it keeps the intent nearest the left rail of the code (in = normal/common-ish coding standards) >=20 > - 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). >=20 > - it has the quality that optional parts are towards the end >=20 > - 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. >=20 > - has the quality of promoting single-line conditional returns >=20 >=20 > # Finally >=20 > One might say this is unnecessary syntactic sugar, which is definitely = arguable. But we do have multiple ways of achieving this. >=20 > Of course all of these things should be discussed, I think sub-votes = (should this PR make it that far) could be considered. >=20 > The PR is located here: >=20 > https://github.com/php/php-src/pull/5552 >=20 > As mentioned, some discussion is happening there as well. >=20 >=20 > Thanks! > Ralph Schindler >=20 >=20 > 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! I'm in favor of language features that encourage defensive coding, so, I = think the concept behind return-if is good, but your approach too = limited. I think a more general guard syntax would be better: guard (some condition) else { //code here must exit the parent block, or else an error is = generated (at compile-time if possible) } This would allow for more and broader use cases: the code in the else = clause could do any of return, continue, break, throw, exit, or maybe = even goto, as appropriate to the condition and its parent block, which = could be any functional block =E2=80=94 a function, loop, if, else, try, = or catch clause, or the "global" scope outside of a function or class = definition. And, if you did return (as opposed to something else), you'd = retain locality of 'return' and the return value, rather than separating = it with the condition. -John