Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: Go 2: call error handling functions with ... #64399

Closed
hauntedness opened this issue Nov 27, 2023 · 11 comments
Closed

proposal: Go 2: call error handling functions with ... #64399

hauntedness opened this issue Nov 27, 2023 · 11 comments
Labels
error-handling Language & library change proposals that are about error handling. LanguageChange Proposal Proposal-FinalCommentPeriod v2 A language change or incompatible library change
Milestone

Comments

@hauntedness
Copy link

hauntedness commented Nov 27, 2023

Proposal Details

In the current Golang language, error handling requires the use of if statements and return values to check and handle errors. While this approach is effective, it introduces a lot of repetitive code and redundant error handling logic in the codebase. To simplify the error handling process, improve code readability, and maintainability, we propose enhancing the error handling syntax sugar in Golang to make it more concise and flexible.

Background:
In the existing Golang language, error handling is typically done as follows:

func Do(param string) (string, error) {
    return "", nil
}

func DoMany(param string) error {
    result, err := Do(param)
    if err != nil {
        return err
    }
    // Handle result
    return nil
}

This approach requires the use of if statements and return values to check and handle errors, resulting in a lot of repetitive code and redundant error handling logic. To simplify the error handling process, improve code readability, and maintainability, we propose enhancing the error handling syntax sugar in Golang.

Proposal:
We propose introducing the following new syntax sugar to simplify error handling in Golang:

  1. Use named optional functions as error handlers:
func check(err error) error {
    return err
}

var nilOrReturn = check

func handle(err error, param string) error {
    return fmt.Errorf("error: %w, param: %s", err, param)
}
  1. Support using syntax sugar to handle errors in function calls:
func DoMany(param string) error {
    // 1. regular error handling
    _, err := Do(param)
    if err != nil {
        return check(err)
    }

    // 2. is syntax sugar of 1
    _, err = Do(param)
    nilOrReturn...(err) // flexible naming notation

    // 3. is syntax sugar of 2, perhaps the most use case
    result1, check...err := Do(param)
    fmt.Println(result1)

    // 4. also support multiple params handler
    _, err = Do(param)
    handle...(err, param)

    // -----------------edge cases-------------------
    // 5. allow omit extra parameter?
    _, err = Do(param)
    handle...(err, /*param: default zero? */ )

    // 6. similar to 5, but a little bit make sense
    _, handle...err = Do(param)

    // 7. syntax error? many conflictions
    _, handle...(err, param) = Do(param)

    // 8. not necessary?
    inverseOrder := func(msg string, err error) error {
        return err
    }
    _, err = Do(param)
    inverseOrder...(param, err)
    return nil
}
  1. Additional Examples:
func Do2(param string) (string, error) {
    return nil, nil
}

func handle2[T any](err error) (T, error) {
    var t T
    return t, err
}

func handleMore[T any](err error, param string) (T, error) {
    var t T
    return t, fmt.Errorf("error: %w, param: %s", err, param)
}

func DoMany2(param string) (string, error) {
    result, handle2[string]...err := Do2(param)
    return result, nil
}

func DoMore(param string) (string, error) {
    result, err := Do2(param)
    handleMore[string]...(err, param)
    return result, nil
}

Apologies in advance for any lack of thoroughness, any suggestion is appreciated.

@gopherbot gopherbot added this to the Proposal milestone Nov 27, 2023
@seankhliao
Copy link
Member

Please fill out https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing language changes

@seankhliao seankhliao added LanguageChange v2 A language change or incompatible library change error-handling Language & library change proposals that are about error handling. labels Nov 27, 2023
@seankhliao seankhliao changed the title proposal: Simplify and Enhancing Error Handling Syntax Sugar in Golang proposal: Go 2: call error handling functions with ... Nov 27, 2023
@seankhliao
Copy link
Member

I don't think it's clear where the conditional branch went?

@seankhliao seankhliao added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Nov 27, 2023
@hauntedness
Copy link
Author

Would you consider yourself a novice, intermediate, or experienced Go programmer?
experienced.
What other languages do you have experience with?
java,scala,javascript,python,rust
Would this change make Go easier or harder to learn, and why?
harder to learn as introduced new syntax.
Has this idea, or one like it, been proposed before?
yes.
If so, how does this proposal differ?
difference to the keyword approach, check, handle:
this proposal allow to capture more variables than the handle clause.
differ from the leftside function: 52416
the leftside function is immediately return for any error while this proprosal allow us handle the error before return.
Who does this proposal help, and why?
all go developer, the code will be less verbose and repetitive.
What is the proposed change?
see #1.
Please describe as precisely as possible the change to the language.
see #1.
What would change in the language spec?
new feature, see #1.
Please also describe the change informally, as in a class teaching Go.
Is this change backward compatible?
yes
Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
Show example code before and after the change.
What is the cost of this proposal? (Every language change has a cost).
How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
many tools affected, eg: vet, linters, gopls, gofmt
What is the compile time cost?
not sure, but I believe it is small
What is the run time cost?
small cost
Can you describe a possible implementation?
No.
Do you have a prototype? (This is not required.)
How would the language spec change?
Orthogonality: how does this change interact or overlap with existing features?
Yes there will be overlap with existing error handling.
Is the goal of this change a performance improvement?
No
If so, what quantifiable improvement should we expect?
How would we measure it?
Does this affect error handling?
If so, how does this differ from previous error handling proposals?
Is this about generics?
If so, how does this relate to the accepted design and other generics proposals?

@hauntedness
Copy link
Author

@seankhliao
The new syntax will either do return or nothing based on the error value. My proposal is below statment will be eventually translated to the idiomatic if err != nil ...

// before
result1, check...err := Do(param)
// after
_, err := Do(param)
if err != nil {
    return check(err)
}

@seankhliao seankhliao removed the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Nov 27, 2023
@adonovan
Copy link
Member

adonovan commented Dec 6, 2023

This seems like another variation on the previous "try" proposal #32437, and it is unclear how it addresses the problems that ultimately caused that proposal to be retracted. Therefore this is a likely decline. Leaving open for a further four weeks for final comments.

@hauntedness
Copy link
Author

hauntedness commented Dec 7, 2023

@adonovan

This seems like another variation on the previous "try" proposal #32437
Agree

and it is unclear how it addresses the problems that ultimately caused that proposal to be retracted. Therefore this is a likely decline. Leaving open for a further four weeks for final comments.

Can you elaborate more on what the unclear is and which the problems are?
From my view, most of the comments on proposal #32437 were meant to improve it but not to retract it.
I can truely find some valuable insights from 32437. And they got many claps, Such as @buchanae

  1. err is implicit in the "try" proposal.
  2. "try" make it hard to add context to error
    image
    image
    While this proposal is slight different to that, check() is not a build in and could do as many transformations as you like. Thus obviously resovle the concern from @griesemer

And I don't want to push anybody, but we have already spent 5 years on bring error handling to go, how many 5 years we still own?

@griesemer
Copy link
Contributor

@hauntedness To start, your proposal is pretty unclear. You introduce a few functions (check, handle) and some syntactic sugar, but you're not explaining how these connect. There are examples that may be clear to you, but they are certainly not clear to everybody else. You are obviously introducing new syntax (the ... in the middle of variable lists) without an explanation or any analysis of how such a syntax change would affect the grammar of the language or whether it might cause problems. It's a pretty big hammer.

Second, as @alandonovan already mentioned, this doesn't look any better (e.g., more lightweight) from just glancing at the examples (which remain unclear) than many of the error handling proposals that came before this one, so it's not clear why this proposal should stand out above the rest.

Finally, Go does have error handling, and it's explicit. It just so happens that in some code that explicit error handling code can be somewhat pervasive, while in other code it's not that pervasive. People who deal with code that have a lot of error handling would like a better solution. Others don't care that much. And again others think that Go's error handling is fine as is. And the split between these groups appears to be somewhat even, making it difficult to push forward an approach that is not obviously superbly better than what we have. And it seems that such an obviously superbly better approach has not yet surfaced (of course, individual authors of error handling proposals may feel differently, but that doesn't matter if not enough people agree). It doesn't seem what you are proposing is obviously superbly better than any of the other proposals that came before this one.

Therefore, this proposal remains a likely decline. Thanks.

@hauntedness
Copy link
Author

@griesemer

To start, your proposal is pretty unclear. You introduce a few functions (check, handle) and some syntactic sugar, but you're not explaining how these connect. There are examples that may be clear to you, but they are certainly not clear to everybody else.

Apologize for causing any understanding difficulty. Although I thought It is quite simple and concise, I am glad to provide more explanations.

// before
result1, check...err := Do(param)
// after
_, err := Do(param)
if err != nil {
    return check(err)
} 

The ... syntax is working like to say code manipulation operator.
There are 2 alternative ways of using.

  • It can also be used in a single statement.
    Then It will simply be translated to a nil error check following a function call following a return.
  • It can be put on the left side of a function call in form of {{$functionName}}...{{$variableName}}
    Then it will firstly create a new line and then do the same as 1st alternative

The handle function is used to handle error,

  • it has at least 1 parameter
  • the 1st parameter must be error type
  • it may return 0 or 1 or more values.
    Below are valid examples.
func check(err error) error
func check[T any](err error) (T, error)
func check[T any](err error, otherArgs ...any) (T, error)

You are obviously introducing new syntax (the ... in the middle of variable lists) without an explanation or any analysis of how such a syntax change would affect the grammar of the language or whether it might cause problems. It's a pretty big hammer.

Excellent point, I insist not to fix the grammar but this do affect the language in many perspectives. And that's why I don't wish this proposal be closed. It is hard to say affects without enough contributes and I ofcourse welcome for comments.

Second, as @alandonovan already mentioned, this doesn't look any better (e.g., more lightweight) from just glancing at the examples (which remain unclear) than many of the error handling proposals that came before this one, so it's not clear why this proposal should stand out above the rest.

Please let's forgot just mentioning many proposals balabala, could you please show me the real point. I believe there were some shining proposals ever appeared, But I suspect they are 'all' declined.
If I must raise out the any better, I already mentioned before.

  1. compare to the "try" proposal, this proposal more more encourage to handle the error in explicit way
    At least from my view, this is the better
  2. compare to the "try" proposal, this proposal allow add context to the error result
    This is the better as well

Finally, Go does have error handling, and it's explicit. It just so happens that in some code that explicit error handling code can be somewhat pervasive, while in other code it's not that pervasive. People who deal with code that have a lot of error handling would like a better solution. Others don't care that much. And again others think that Go's error handling is fine as is. And the split between these groups appears to be somewhat even, making it difficult to push forward an approach that is not obviously superbly better than what we have. And it seems that such an obviously superbly better approach has not yet surfaced (of course, individual authors of error handling proposals may feel differently, but that doesn't matter if not enough people agree). It doesn't seem what you are proposing is obviously superbly better than any of the other proposals that came before this one.

Sorry for the inaccuracy words. Yes, agree with most of the comments. I know it is hard to reach consesus, I wish we can achieve it quickly while I also understand how hard it is. But from my point, we'd better encourage ideas rather than do nothing.

@griesemer
Copy link
Contributor

Per

// before
result1, check...err := Do(param)
// after
_, err := Do(param)
if err != nil {
    return check(err)
}

check...err is translated into the "after" code, is that correct? Can I write something else than check? Can I write foo...err (and define a foo function)? These are things that all need to be clarified.

I also point out that the use of ... in this context looks very odd. ... is not used elsewhere in Go as a "code manipulation operator", so it seems unwise to give it some completely different meaning. It's unclear what it means for ... to be on the left side of a function call.

But separately, the syntax you're implying with your examples is unlike anything else we have in Go. There's no convincing argument why this is any better than any of the many other error handling proposals.

@hauntedness
Copy link
Author

check...err is translated into the "after" code, is that correct? Can I write something else than check? Can I write foo...err (and define a foo function)? These are things that all need to be clarified.
Correct and Yes and Yes.

@findleyr
Copy link
Contributor

No change in consensus, so declined.
— rfindley for the language proposal review group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
error-handling Language & library change proposals that are about error handling. LanguageChange Proposal Proposal-FinalCommentPeriod v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

6 participants