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.
👍