Skip to content

Instantly share code, notes, and snippets.

@dpremus
Created November 12, 2018 14:31
Show Gist options
  • Save dpremus/3b141157e7e47418ca6ccb1fc0210fc7 to your computer and use it in GitHub Desktop.
Save dpremus/3b141157e7e47418ca6ccb1fc0210fc7 to your computer and use it in GitHub Desktop.
Go 2 Error handling
Copy link

ghost commented Dec 12, 2018

I like this proposed method above. For my own projects I adopt when possible using labels to jump below the "fall through" return in the function as it seems to make the cleanest code so not far off from this proposal at all. Below is my thinking on various options using labels, I hope this opens up more thoughts on possibilities.

// If you are going handle an error immediately 
// then why create it per function? Might as well just 
// reuse a global error variable most of the time rather 
// than constantly create and destroy the same variable type 
// unless this has problems with channels or some such 
// thing.
var Err error

// Dummy function for example only, 
// do not try to run.
func doSomething (v string) string {
	var result string

	// If we are going to do nothing on error 
	// just do your check and return.
	result, Err = Operation1(v)
	if Err != nil {
		return result
    }
	result, Err = Operation2(v)
	if Err != nil {
		return result
    }

	// If we are going to do "a same thing" on
	// various errors then go to a place where
	// we do a same thing and avoid repeating code.
	result, Err = Operation3(v)
	if Err != nil {
		goto errLog
    }
	result, Err = Operation4(v)
	if Err != nil {
		goto errLog
    }

	// We can do more than one "same thing" and 
	// keep it reasonably clean.
	result, Err = Operation5(v)
	if Err != nil {
		goto errLogExit
    }
	result, Err = Operation6(v)
	if Err != nil {
		goto errLogExit
    }

	// An even cleaner way for when we are doing
	// a "same thing" on error many times would be 
	// to setup an implicit goto but this might make
	// it a little too easy to make a mistake by 
	// forgetting it's going to a particular place.
	// I personally don't have a problem with this but
	// I could see that argument being made.
	// Regardless, the "cleanliness" of this method is 
	// compelling.
	on error goto ErrLogImplicit
	result, Err = Operation7(v)
	result, Err = Operation8(v)

	// Go doesn't promote multiple statements on one line 
	// but sometimes can be the best way for readability.
	on error goto ErrLog2; result, Err = Operation9(v)
	on error goto ErrLog1; result, Err = Operation10(v)
	on error goto ErrLog2; result, Err = Operation11(v)

	// Or like the above example, which I like:
	result, @ErrLog2 = Operation9(v)
	result, @ErrLog1 = Operation10(v)
	result, @ErrLog2 = Operation11(v)
	
	return result

ErrLog:
    Logger(Err)
	return result

ErrLogExit:
    Logger(Err)
	os.Exit(5)

ErrLogImplicit:
    Logger(Err)
	DoAnotherThing()
	return result

ErrLog1:
    Logger(Err)
	DoAThing1()
	return result

ErrLog2:
    Logger(Err)
	DoAThing2()
	return result
}

I should add that I am all for having more than one method of error handling as I don't think "one size fits all" is a good approach to error handling. The standard "check error on return from function" plus one or two methods for jumping to an error handling point to me makes the most sense for having cleaner code.

I've ignored a central error handler for the entire app. like PHP has which I like having done a lot of PHP work but I suspect it wouldn't fit in with the "Go" way.

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