Skip to content

Instantly share code, notes, and snippets.

@yaxinlx
Last active September 24, 2019 12:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yaxinlx/1e013fec0e3c2469f97074dbf5d2e2c0 to your computer and use it in GitHub Desktop.
Save yaxinlx/1e013fec0e3c2469f97074dbf5d2e2c0 to your computer and use it in GitHub Desktop.
A Go 2 error handling propsoal

Use ? as suffixes of multi-value tuples to remove the last error value from multi-value tuples

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.

The syntax

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.

Examples

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
	}
	...
}
@honzajde
Copy link

How about to use operator :=? (or :=?? etc.) instead, which does the same.

@yaxinlx
Copy link
Author

yaxinlx commented Sep 24, 2019

How about to use operator :=? (or :=?? etc.) instead, which does the same.

I don't have a clear opinion on this. Maybe if err != nil {...} is not bad. ;D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment