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: add try statement to specify handler for unhandled errors #35179

Open
aminsol opened this issue Oct 26, 2019 · 4 comments

Comments

@aminsol
Copy link

@aminsol aminsol commented Oct 26, 2019

Summary

This is a proposal to address the issue of go with "too much code checking errors and not enough code handling them."

Goals

  • Reduce the number of code checking

  • Backward compatibility

  • Increase readability

  • Familiar syntax

  • Less writing

Introduction

This proposal creates a new statement, try, alongside the current method of handling the errors. The proposed statement try takes one function as an argument, and the passed function will be called if there is an unhandled error.
An unhandled error is an error that it was returned, and it is not null, but no variable is defined to receive it.

Try (handler func)

Try will allow a block of code to trigger the handler function when an unhandled error occurs. The unhandled error will be passed to try as a parameter. Try will continue the block of code after triggering the handler function unless the handler function returns something(not null) or terminates the program.

Parameter: handler function

Removing Tailing Variable

In try block, we can remove the tailing variable, which represents an error. If any error occurs, our handler function receives it, and it would be handled.

x, err := strconv.Atoi(a)
y, err := strconv.Atoi(b)
z, err := strconv.Atoi(c)

to

try(handler){
x := strconv.Atoi(a)
y := strconv.Atoi(b)
z := strconv.Atoi(c)
}

Example

Proposed Way

// Generic Error Handler
handler := func(err error) {
    fmt.Println("Warning: ", err)
}

a := "not Integer"
b := "not Integer"
c := "not Integer"

try(handler){
    x := strconv.Atoi(a) // <---- This will tigger our handler function
    y := strconv.Atoi(b) // <---- This will tigger our handler function
    z, err := strconv.Atoi(c) // <---- This will NOT tigger our handler function
    if err != nil {
        panic("We cannot convert c to int")   
    }
}

The Same Code in go

a := "not Integer"
b := "not Integer"
c := "not Integer"

x, err := strconv.Atoi(a)
if err != nil {
    fmt.Println("Warning: ", err)
}

y, err := strconv.Atoi(b)
if err != nil {
    fmt.Println("Warning: ", err)
}

z, err := strconv.Atoi(c)
if err != nil {
    panic("We cannot convert c to int")
}

Conclusion

Try will be an excellent tool for handling generic errors and simplifying our code. The proposed way is one of the least ugly ways to reduce the number of code checking in Go.

@gopherbot gopherbot added this to the Proposal milestone Oct 26, 2019
@gopherbot gopherbot added the Proposal label Oct 26, 2019
@aminsol aminsol changed the title Proposal: Go2 Error checking and handling Errors inspired by JavaScript Proposal: Go2: Error checking and handling Errors inspired by JavaScript Oct 26, 2019
@ianlancetaylor ianlancetaylor changed the title Proposal: Go2: Error checking and handling Errors inspired by JavaScript proposal: Go 2: add try statement to specify handler for unhandled errors Oct 26, 2019
@gertcuykens

This comment has been minimized.

Copy link
Contributor

@gertcuykens gertcuykens commented Oct 28, 2019

I used to think top down from a user perspective but now I think bottom up from a compiler perspective. I realy realy underestimated how difficult compilers can be even for the go language. I am not saying your proposal is bad, I just have a feeling this proposal requires another big chunk of complex compiler code to be written and introduces more edge cases like where to put defer statements. That said I can also imagine code where this try block is excedeling big.

@deanveloper

This comment has been minimized.

Copy link

@deanveloper deanveloper commented Nov 6, 2019

This suffers from the pitfall that error-prone functions are no longer annotated in any way, which was a huge problem that comes from the traditional try-catch approach.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Nov 19, 2019

If a function called within a try block adds or remove an error result, that can significantly and silently change how the code executes, which seems very problematic.

Various similar ideas have been proposed in the past, such as #33002.

This proposal does not have strong support.

For these reasons, this is a likely decline. Leaving open for four weeks for final comments.

@KevinJCross

This comment has been minimized.

Copy link

@KevinJCross KevinJCross commented Nov 22, 2019

The trailing error is interesting but what about this syntax below ?

func call1() {...} int, error
func call2() {...} int, error
func call3() {...} int, error
func example() error {
    sum, err :=  try{ return call1() + call2() + call3() }()
    if err != nil {
      ....
    }
   doSomethingWithSum(sum)
   return nil
}

where the try is a generated compiled "generic function" that bails on the first non nil returned error
that might look something like this

func _some_generated_name() (int, error) {
   x1, err = call1()
  if ( err != nil ){
    return x1, err
  }
   x2, err = call2()
  if ( err != nil ){
    return x2, err
  }
  x3, err = call3()
  if ( err != nil ){
    return x3, err
  }
  return x1 + x2 + x3, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
7 participants
You can’t perform that action at this time.