The Go 2 Error Handling proposal
introduces 2 new keywords to the Go programming language, handle and catch. This means any Go 1 code that uses the
names handle or catch as variable or method names (I have often used the method name handle) will no longer compile.
Despite the proposals suggestion that check
is somehow different from try, for the most part it isn't. The Go 1 FAQ explains
why Go does not have try-catch-finally with one of the reasons being that it leads to convoluted code.
The explicit requirement to check errors as they happen in the past was a feature of Go, not a mistake.
The proposal on the board does eliminate finally, but not the try-catch part.
This proposal does limit the try-catch paradigm to a function's scope, the execeptions do not unwind up the stack, which
is a minor improvement over Python's try-catch, but that is not the only issue with try-catch. Take the small example
in the proposal:
func main() {
handle err {
log.Fatal(err)
}
hex := check ioutil.ReadAll(os.Stdin)
data := check parseHexdump(string(hex))
os.Stdout.Write(data)
}
The handler does not know which of the functions generated the error. Imagine there are a dozen calls to check inside
the function. The handle is applied to all of them. This is lazy code writing.
I can easily see this proposal leading to code like:
func foo() error {
var a sometype
var b anothertype
{
handle err { some handling code }
a = check func1()
check func2(a)
}
{
handle err { some other handling code }
b := check func3(a)
check fmt.Printf("B is %v\n", b)
}
check func4(a, b)
}
This could made a bit easier if you could delete a handler:
func foo() error {
h1 := handle err { some handling code }
a := check func1()
check func2(a)
delete(h1)
h2 := handle err { some other handling code }
b := check func3(a)
check fmt.Printf("B is %v\n", b)
delete (h2)
check func4(a, b)
}
This at least removes the extra scopes and the needing to pre-declare a and b. This syntax does have drawbacks:
func foo() error {
h := handle err { some handling code }
a := check func1()
check func2(a)
h = handle err { some other handling code }
b := check func3(a)
check fmt.Printf("B is %v\n", b)
delete (h)
check func4(a, b)
}
The second handle call makes it look like the first handler will be deleted, but of course, it will not be.
For the record, I don't like this either.
I agree that it sometimes can be a little annoying to add add two dozen extra keystrokes just to check for an
error that you don't expect to really happen all that much. While I agree that it is easier to write a = check foo()
rather than if a, err = foo(); err != nil { return err }, I do believe it will lead to code that does not properly
handle errors.
👍