go: proposal: Go 2: use keywords throw, catch, and guard to handle errors
The proposal borrowed some ideas from The check/handle proposal. One of the issues of “check/handle proposal” is that it doesn’t support function chaining well: https://gist.github.com/DeedleFake/5e8e9e39203dff4839793981f79123aa.
To make a long story short, let’s see some code examples first.
Without the proposal:
type data struct {}
func (d data) bar() (string, error) {
return "", errors.New("err")
}
func foo() (data, error) {
return data{}, errors.New("err")
}
func do () (string, error) {
d, err := foo()
if err != nil {
return "", err
}
s, err := d.bar()
if err != nil {
return "", err
}
return s, nil
}
With the proposal:
type data struct {}
func (d data) bar() string {
// The throw is like the return, you have to state the origin return values with an extra error.
// The last value of the list must fulfil error interface, or compile error.
throw "", errors.New("err")
}
func foo() (d data) {
// Same as the return, in this case we can omit the return values.
throw errors.New("err")
// Throw is like return, this line is unreachable.
return
}
func do () (string, error) {
// The catch is similar to the handle in the check/handle proposal.
catch err { // the type of err is error
return "", err // you must return corresponding values just like a normal function
}
// The error will propagate like the panic until it's caught by a `catch` clause.
s := foo().bar()
return s, nil
}
Use keyword guard to convert the throw version to normal error value style, so that we can precisely handle each error separately:
func do () (string, error) {
d, err := guard foo()
if err != nil {
return "", err
}
s, err := guard d.bar()
if err != nil {
return "", err
}
return s, nil
}
Currently, I created a demo lib to simulate the taste: https://github.com/ysmood/tcg/blob/master/example_test.go
We shouldn’t just use the panic to do it. For the implementation of throw, it’s similar to setjmp and longjmp. I feel the performance won’t be affected.
To avoid forgetting catch we can statically do something similar to https://github.com/kisielk/errcheck by analyzing throw keyword.
Sure the keywords are not decided, we can use other words if they are better.
Would you consider yourself a novice, intermediate, or experienced Go programmer?
Experienced
What other languages do you have experience with?
js, ruby, elixir, scala,c, c#, python, haskell, php, lua
Would this change make Go easier or harder to learn, and why?
Harder
Has this idea, or one like it, been proposed before?
Have researched the https://github.com/golang/go/issues/40432, not able to find similar ones.
Who does this proposal help, and why?
Everyone, because error handling is used in most of projects.
What is the proposed change?
See the front description.
Is this change backward compatible?
No, it will add new keywords.
What is the cost of this proposal? (Every language change has a cost).
Users have to spend more time to master the error handling.
How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
All of them.
What is the compile time cost?
Minor cost.
What is the run time cost?
Minor cost.
Can you describe a possible implementation?
Only if we agree with this idea.
Do you have a prototype? (This is not required.)
No
How would the language spec change?
See the front description.
Orthogonality: how does this change interact or overlap with existing features?
Might overlap the panic.
Is the goal of this change a performance improvement?
No.
Does this affect error handling?
Yes.
If so, how does this differ from previous error handling proposals?
See the front description.
Is this about generics?
No.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 65
- Comments: 24 (12 by maintainers)
In the strongest possible terms, no.
Based on the discussion above and the emoji voting, this is a likely decline. Leaving open for four weeks for final comments.
Throws semantics need to be explicitly defined as its introduces new control flow. What happens when a throw is executed in a defer? Do the other defers still run?
This is not possible statically when reflect Call, function variables and plugins are involved without explicit anotation.
Errors are different in that the function signature shows explicitly whether an error is returned or not.
See https://github.com/golang/go/issues/40432.
Especially: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md For why implicit checking/implicit results is not prefered for error handling.
@ysmood this may be useful for your proposal. https://github.com/golang/proposal#proposing-changes-to-go
Have you seen https://golang.org/doc/faq#exceptions ?
That said:
I don’t understand the difference between
throwandpanic.I don’t understand the difference between
catchand a deferred function that callsrecover.I don’t understand the difference between
guardandTrue but there was no claim here that its possible to know where all error values are originating from either. Errors dominately are returned as error types directly which is possible to analyse statically and not as
interface{}. This analysis also doesnt need whole program inter package analysis as knowing function signatures is enough. As there would be no explicit annotation for throws the analysis is quite a bit harder and has more commonly used language cases like function variables and reflect Calls where it will expensive or not knowable if a throw can happen.For language change proposals, please fill out the template at https://go.googlesource.com/proposal/+/refs/heads/master/go2-language-changes.md .
When you are done, please reply to the issue with
@gopherbotpleaseremovelabelWaitingForInfo.Thanks!