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: error handling with magic .handleErr() method #56126

Closed
AAlvarez90 opened this issue Oct 10, 2022 · 3 comments
Closed

proposal: Go 2: error handling with magic .handleErr() method #56126

AAlvarez90 opened this issue Oct 10, 2022 · 3 comments
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal Proposal-FinalCommentPeriod v2 A language change or incompatible library change
Milestone

Comments

@AAlvarez90
Copy link

AAlvarez90 commented Oct 10, 2022

Author background

  • Would you consider yourself a novice, intermediate, or experienced Go programmer? Intermediate
  • What other languages do you have experience with? C & C++/Java/Javascript/Ruby/PHP/Rust/Assembly/Go

Related proposals

  • Has this idea, or one like it, been proposed before? No that I am aware of.
    • If so, how does this proposal differ?
  • Does this affect error handling? Yes
    • If so, how does this differ from previous error handling proposals? Not aware of another proposal like the one I am about to create
  • Is this about generics? No
    • If so, how does this relate to the accepted design and other generics proposals?

Proposal

  • What is the proposed change?
    I propose to add a new method which can be named handleErr, unwrap or expect or to any function operation that may return a value and an error or just an error. Currently error handling feels very repetitive in many cases. After using a function we need to add about 3 lines of code to test if err != nil. What I am proposing would allow us to accomplish the same but with less code. I am not proposing to replace the existing error handling but to enhance it.
    I have been inspired by the same functionality that is available in Rust.

  • Who does this proposal help, and why?
    It helps to handle errors with less code.

  • Please describe as precisely as possible the change to the language.
    We would enhance the existing error handling mechanism by adding special functions which are evaluated at compile time and have the compiler either add code for us (add the classic if statements we would add) or exit the enclosing function's execution while simulating the same thing that happens when we manually return the error.

    • Before
func ExpelUser(userId int) error {
    
    err := findUserAndFlag(userId)
    if err != nil {
        return err
    }

    err = executeAction2(userId)
    if err != nil {
        return err
    }

    err = closeAccountAndPayUserOff(userId)
    if err != nil {
        return err
    }
    return nil
}
  • After
func ExpelUser(userId int) error {
    
    // Ends execution of ExpelUser and returns the error that findUserAndFlag returned if it's not nil
    findUserAndFlag(userId).handleErr()

    executeAction2(userId).handleErr()

    // Returns a different type of error
    closeAccountAndPayUserOff(userId).handleErr(errors.New("Error closing account"))

    return nil
}

Another example is when the function is supposed to return a value and an error

  • Before
func FindRecordOrCreateIt(data map[string]interface{}, existingId int) Record, error {
    record := new(Record)
    
    err := database.FindRecordById(&record, id)
   
     // Something else happened other than the expected NotFound
    if !err.Is(database.ErrNotFound) {
        return record, err
    }

    if record.ID != 0 {
        return record, err
    }

    err = validateUserCreateData(data)
    if err != nil {
        return err
    }

    err = createUser(&record, data)
    if err != nil {
        return err
    }
    
     return record, nil
}
  • After
func FindRecordOrCreateIt(data map[string]interface{}, existingId int) Record, error {
    record := new(Record)
    
    // Check if the error is not sentinel error database.ErrNotFound and return it along with record
    err := database.FindRecordById(&record, id).handleErrAgainst(record, database.ErrNotFound)

    if record.ID != 0 {
        return record, err
    }

    validateUserCreateData(data).handleErr()
    createUser(&record, data).handleErr()
    
    return record, nil
}

Costs

  • Would this change make Go easier or harder to learn, and why?
    I think it would make Go more enjoyable, specially around the error handling area.
    In Go we are expected to treat "Expected Errors" as error values (sentinel errors) and "Unexpected errors/Exceptions" as Error Types but we incur in a lot of IF statement repetitions to accomplish error handling. What I am proposing is to de-load the usage of if statements to check errors and return them and have a special way of dealing with that so we use IF statements to check application logic rather than both (logic and error handling).

  • Implementation tips
    As the first pass, we can have the compiler write the if statement for us when encounters a function call followed by a call to one of the special functions. Just like we do with the * and pointers. Then, in a future implementation a more comprehensive approach could be implemented.

@gopherbot gopherbot added this to the Proposal milestone Oct 10, 2022
@seankhliao seankhliao added LanguageChange v2 A language change or incompatible library change error-handling Language & library change proposals that are about error handling. labels Oct 10, 2022
@ianlancetaylor
Copy link
Contributor

Thanks. Please see #40432. This seems fairly similar to some existing proposals. It seems to imply somewhat hidden flow of control, as in x := f1().handleErr() + f2().handleErr(), which can return from the function after calling f1 but before calling `f2. We've consistently rejected proposals with this kind of flow of control in the middle of an expression.

@seankhliao seankhliao changed the title proposal: Go 2: proposal: Go 2: error handling with magic .handleErr() method Oct 12, 2022
@ianlancetaylor
Copy link
Contributor

Based on the comment and the emoji voting, this is a likely decline. Leaving open for four weeks for final comments.

@ianlancetaylor
Copy link
Contributor

No further comments.

@ianlancetaylor ianlancetaylor closed this as not planned Won't fix, can't repro, duplicate, stale Dec 7, 2022
@golang golang locked and limited conversation to collaborators Dec 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
error-handling Language & library change proposals that are about error handling. FrozenDueToAge LanguageChange Proposal Proposal-FinalCommentPeriod v2 A language change or incompatible library change
Projects
None yet
Development

No branches or pull requests

4 participants