On Wed, Nov 11, 2020 at 2:43 AM Jeremy French <ibi...@gmail.com> wrote:
> I certainly can't speak for the whole community, but for me, the key word > here is verbosity. I don't care (too much) whether it's technically a > statement or an expression or a macro. What I care about is signal to noise > ratio in my code. What I really want in my fantasies is for my code to be > 100% happy path. > The majority (or maybe the loud minority - either way, definitely Go's design philosophy) of the community disagrees with you here. Error handling should be explicit, that seems to be a hard requirement. > I'm wondering if people object more to that or to the fact that the > surrounding "if" qualifies as a statement rather than an expression. > What I'm saying is that one causes the other. You mention the 25% ratio. That ratio is based on line-count and the only reason why the error-handling takes up more lines, is because it uses a statement. So my point is, to meaningfully reduce the "verbosity", you have to get away from that. Incidentally, this is also why I think this version of returnif is > critically different from the version that reads "returnif <err>" because > it doesn't require the compiler/runtime to know what an error is or when it > should qualify as something that needs to be returned. > I agree. I disagree that it's critically different from what we have today. > In the two-expression version, the developer is in complete control. > > -- > > >> >> 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 <(607)%20444-1725> >>>> >>>> On Mon, Nov 9, 2020, 2:57 PM Ian Lance Taylor <ia...@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...@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...@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/fd01a242-c89d-4ab9-8266-c0f61cf177f6n%40googlegroups.com > <https://groups.google.com/d/msgid/golang-nuts/fd01a242-c89d-4ab9-8266-c0f61cf177f6n%40googlegroups.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/CAEkBMfEj8oKaVT9GgTdxwGc8JKy2kH5_mysGqf%2B7kFYkG0d5%2Bg%40mail.gmail.com.