IMO, `returnif <bool>, <expr...>` reads awkwardly. If anything, it should really be `return <expr...> if <bool>`. At which point it also becomes clear that this isn't actually much of an improvement over `if <bool> { return <expr...> }`.
On Tue, Nov 10, 2020 at 11:59 PM Tyler Compton <xavi...@gmail.com> wrote: > The "try proposal" and some others identified and solved two problems: > > a. The verbosity of using a full if statement to check error values > b. The verbosity of applying wrapping and other error handling logic to > every place where an error is returned > > This proposal only addresses Problem A. Maybe that's okay, because it > seems like addressing Problem B often leads to complicated control flow > issues. > The way I think about it at least, is that the try proposal was rejected *because* it solved problem A specifically (and the returnif mentioned here doesn't; `returnif` stays a statement). The main criticism of try, as far as I remember, was that in something like `F(try G(), try H())` it wasn't clear enough how the control flow worked. But that's a direct consequence of creating an error handling *expression* (as opposed to a statement). Realizing that was the point where I kind of gave up on the idea of ever "solving" the error handling problem. To me, error handling requiring a statement is the main gripe of most people - it's why it seems verbose and repetitive to people. But if that's so, but the community rejects any proposal that makes it an expression, then the problem becomes unsolvable. > I do like that this proposal doesn't treat errors in a special way. I > could imagine it could be useful when checking if a key is in a map, for > example. > > value, ok := myMap["value"] > returnif !ok, errors.New("Oh no! Missing key 'value'!") > > Another thought: Should returnif allow a statement before the boolean > expression like if does? > > returnif value, ok := myMap["value"]; !ok, errors.New("Oh no!") > > That could make code more compact but looks very busy to me. My first > impression is that this shouldn't be allowed. > > I think I would be okay with reading and writing code like this. The level > of complexity here is certainly lower than other proposals, although the > value is arguably lower as well since it doesn't solve as many problems. > I'll defer to others here. > > > On Mon, Nov 9, 2020 at 1:52 PM Jeremy French <ibi...@gmail.com> wrote: > >> Hm, yep. Very similar. Interestingly, the only cohesive objections I can >> see in those threads are to the minor details that are different from what >> I'm saying. Still, though - at least the idea has been presented before. >> >> Jeremy French >> 607-444-1725 >> >> On Mon, Nov 9, 2020, 2:57 PM Ian Lance Taylor <i...@golang.org> wrote: >> >>> On Mon, Nov 9, 2020 at 11:20 AM Jeremy French <ibi...@gmail.com> wrote: >>> > >>> > First, the caveat. I know error handling is a long-standing >>> discussion. I know there has been lots of debate on error handling, and it >>> can seem like there are no more new ideas to be had on the topic. And I >>> have looked at several/most of the most popular proposals, and there are >>> quite a few that bear similarity but are critically different in important >>> aspects to this proposal. If this has been proposed before with the same >>> effective fingerprint, I haven't been able to find it after several hours >>> of due diligence. I'm interested in hearing any and all (well-reasoned) >>> thoughts on the matter, but if there's a flaw in my logic, I don't see it >>> yet. >>> > >>> > In short, the proposal is to create a conditional return statement, >>> e.g. "returnif" of the form: >>> > returnif [bool], [returnvalue],... >>> > >>> > This is syntactic sugar for: >>> > if [bool] { >>> > return [returnvalue],... >>> > } >>> > >>> > of which, the immediate benefit is: >>> > returnif err!=nil, err >>> > >>> > or alternatively: >>> > >>> > returnif myErrorChecker(err), myErrorWrapper(err, "Some text.") >>> > >>> > Here's my reasoning. Go Error Handling in is current form is >>> extremely correct, precise, explicit, and clear. All very good things. >>> Really the only problem with it is the repetitious verbosity. A >>> programmer's instinctive reaction to repetitious verbosity is to wrap it in >>> a function. The infamous "if err != nil {return err}", although >>> repetitious and ubiquitous, cannot effectively be encapsulated to "return >>> someErrorChecker()", because the return statement is unconditional. Once I >>> start a statement with return, nothing I can do later in the statement or >>> within a called function can change whether or how that return alters flow >>> control. This, I think, is the quintessential problem with the current >>> error handling methodology. This proposal addresses that without >>> sacrificing any of the good things about error handling in Go. Error >>> handling is still explicit. Errors can still be treated as values. Proper >>> error handling and annotating is blessed but optional. The behavior of >>> defer is unaffected. It is still simple to understand, and easy to read. >>> And it's entirely backwards compatible. >>> > >>> > Also, while the most obvious benefit is in error handling, this is not >>> technically just an error handling solution. It is completely unopinionated >>> on the type of values it returns, or whether they qualify as an error or >>> not. I can foresee enterprising gophers finding other uses for this >>> keyword, and quite possibly even new useful design patterns could emerge as >>> a result. >>> > >>> > Possible Objections: >>> > >>> > It could be seen to violate the "one way to do things" principle. >>> However, >>> > >>> > It violates this rule much less than almost all of the other proposals >>> for error handling. >>> > If, under the covers, it's just code substitution, then there's still >>> only one actual avenue of execution in the compiled objects. >>> > There is precedent for this type of shortcut when the benefits are so >>> widespread and the sugar improves readability. For example, >>> > } else if isTrue { >>> > doSomething() >>> > } >>> > is sugar for >>> > } else { >>> > if isTrue { >>> > doSomething() >>> > } >>> > } >>> > >>> > "It's just a variation on other existing proposals." >>> > >>> > This proposal avoids or addresses all the objections listed in the >>> error handling meta issue #40432, and as such, may be a variation, but >>> varies sufficiently to create a different result set. >>> > From the meta issue: >>> > >>> > The check/handle proposal. >>> > >>> > One major reason this was rejected was a lack of clarity between >>> handle and defer. >>> > >>> > The try proposal. >>> > >>> > One major reason this was rejected was the additional flow control: a >>> complex expression using try could cause the function to return. Go >>> currently has no flow control constructs at the expression level, other >>> than panic which does more than just return from a function. >>> > >>> > Special characters, often ! or ?, that insert an error check in a >>> function call or assignment. >>> > >>> > These are typically rejected because they are cryptic. Often a single >>> ! or other character leads to a change in flow control. >>> > >>> > Simplifications of if err != nil, to reduce boilerplate. >>> > >>> > These are typically rejected either because they don't reduce the >>> boilerplate enough to make it worth changing the language, or because they >>> are cryptic. >>> > >>> > What about edge cases? How to handle else clauses or additional >>> conditional logic based on error type etc.? >>> > >>> > It's my belief that else clauses too rare to justify additional >>> syntax. If you need an else/else if clause, you can use the existing >>> syntax and lay out your conditionals on more lines. Also - you know - any >>> code after a return statement is essential an else clause anyway. >>> > By making [bool] an expression, any additional logic may be handled by >>> the programmer in a determinant function that returns a boolean. This puts >>> this type of flow control in the hands of the developer. >>> > The short statement currently available with if and for statements (if >>> err:=doSomething(); err != nil) could be implemented in a similar fashion, >>> but my personal vote would be to disallow it, as most of the simplicity and >>> clarity of this proposal could be lost down that rabbit hole. >>> > >>> > I believe the most critical difference between this proposal and >>> previous ones is that this proposal addresses the core issue more >>> directly. The central problem to the current error handling methodology is >>> not actually specific to error handling. That's just where it's most >>> visible. The core problem is essentially the fact that a child function >>> cannot affect the conditional return of a parent function (barring further >>> conditional logic), even with explicit permission by the parent function. >>> This is not true with any other form of flow control. This is why the >>> current methodology feels wrong to developers, because they are disallowed >>> from encapsulating repetitious logic in a way that is consistent with other >>> flow control statements. >>> > >>> > Anyway, that's my argument. If anyone knows of a previous proposal >>> that this duplicates, and/or knows why that one didn't/couldn't work, I'd >>> be grateful for the explanation. >>> >>> For the record, similar but not quite identical: >>> >>> https://github.com/golang/go/issues/21161#issuecomment-366766924 >>> https://github.com/golang/go/issues/32811#issuecomment-508776641 >>> >>> Ian >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/CA%2Bj6mhDjFAjpQTcpA3oJfwFKUYdhNn-1jB39FiYoe6nspUTg2g%40mail.gmail.com >> <https://groups.google.com/d/msgid/golang-nuts/CA%2Bj6mhDjFAjpQTcpA3oJfwFKUYdhNn-1jB39FiYoe6nspUTg2g%40mail.gmail.com?utm_medium=email&utm_source=footer> >> . >> > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CAA%3DXfu1RXATObiH-Lx_ZUQXqtT6DyJdR%3Dk9dbg-1KaMNoDL_wA%40mail.gmail.com > <https://groups.google.com/d/msgid/golang-nuts/CAA%3DXfu1RXATObiH-Lx_ZUQXqtT6DyJdR%3Dk9dbg-1KaMNoDL_wA%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfEcqx0QT_eCDTqT%3DvE8%2Bkuxi7A6WPY0A7McaoHHnJ5o2Q%40mail.gmail.com.