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, 
      1. It violates this rule much less than almost all of the other 
      proposals for error handling.
      2. If, under the covers, it's just code substitution, then there's 
      still only one actual avenue of execution in the compiled objects.
      3. 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 <https://github.com/golang/go/issues/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 
         
<https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling.md>
         .
            - One major reason this was rejected was a lack of clarity 
            between handle and defer.
         - The try proposal <https://golang.org/issue/32437>.
            - 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.

-- 
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/f803b120-5340-45ea-9a0c-802488801da3n%40googlegroups.com.

Reply via email to