This proposal is against the handle
part of Go 2 error handling draft design,
and use a new syntax to replace the check
syntax in Go 2 error handling draft design.
I think Go 2 error handling draft design does too much.
It makes many considerations for many rare cases.
However, what we need is just to avoid many if err != nil {return ..., err}
boilerplates.
As Go specification mentions,
fucntion returns are called tuples.
If the last value in a tuple t
is an error
value,
then we can use the syntax form t?
to remove the last error
value from tuple t
.
The result is still a tuple.
The syntax form can only be used in the body of a function which last return result is an error
.
If the removed error
value is not nil, then its inner-most containing function returns immediately.
The last return result is the removed error
value.
Other return results are zero values of their respective types.
Example I:
func foo(x int) (int, error) {
if x < 0 {
return 0, errors.New("invalid input")
}
...
return x+x, nil
}
func bar() error {
...
v := foo(-1)?
...
}
// The above bar function is quivalent to the following one.
func bar() (string, error) {
...
v, err := foo(-1)
if err != nil {
return "", err
}
...
}
Example II:
func f1(x int) (int, error) {
if x < 0 {
return 0, errors.New("invalid input")
}
...
return x+x, nil
}
func f2(x int) (int, error) {
if x == 0 {
return 0, errors.New("invalid input")
}
...
return 100/x, nil
}
func f3(x int) (int, error) {
if x > 0 {
return 0, errors.New("invalid input")
}
...
return -x, nil
}
func bar() error {
...
v := f1(8)? + f2(6)? + f3(-5)?
...
}
// The above bar function is quivalent to the following one.
func bar() (string, error) {
...
v1, err := f1(8)
if err != nil {
return "", err
}
v2, err := f2(6)
if err != nil {
return "", err
}
v3, err := f3(-5)
if err != nil {
return "", err
}
v := v1 + v2 + v3
...
}
func foo() (string, error) {
...
v := f3(f2(f1(8)?)?)?
...
}
// The above bar function is quivalent to the following one.
func foo() (string, error) {
...
v1, err := f1(8)
if err != nil {
return "", err
}
v2, err := f2(v1)
if err != nil {
return "", err
}
v, err := f3(v2)
if err != nil {
return "", err
}
...
}
Example III:
func foo(x, y int) (int, error, error) {
if x < 0 {
return 0, errors.New("invalid input x"), nil
}
if y < 0 {
return 0, nil, errors.New("invalid input y")
}
...
return x+y, nil, nil
}
func bar0() error {
...
v := foo(1, 2)??
...
}
func bar1() error {
...
v, err := foo(1, 2)?
err?
...
}
func bar2() error {
...
v, err1, err2 := foo(1, 2)
err1?
err2?
...
}
// The above barN functions is quivalent to the following one.
func bar() (string, error) {
...
v, err1, err2 := foo(-1)
if err1 != nil {
return v, err1
}
if err2 != nil {
return v, err2
}
...
}
How about to use operator :=? (or :=?? etc.) instead, which does the same.