func read_file(filename string) (string, error) {
return "", errors.New("oops")
}
func foo() error {
a, err := read_file("a.txt")
if err != nil {
return errors.New(fmt.Sprintf("read a: %s", err))
}
b, err := read_file("b.txt")
if err != nil {
return errors.New(fmt.Sprintf("read b: %s", err))
}
// do stuff with a and b
return nil
}
func main() {
err := foo()
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
In a language with exceptions: func read_file(filename string) string {
throw FileNotFound(filename)
}
func foo() {
a := read_file("a.txt")
b := read_file("b.txt")
// do stuff with a and b
}
func main() {
try {
foo()
}
catch (err FileNotFound) {
fmt.Fprintf(os.Stderr, "file not found: %s\n%s\n", err.filename, err.Stacktrace())
}
}
With the current go error handling, you need to add the informations yourself in the string, not as a real data structure.And before you say "you can add the filename to the error message in read_file()", what if the function is defined in a dependency you have no control over?
An exception is a typed data structure that contains way more informations and value to automate rescuing.
Delegating error handling to a try/catch block with a typed data structure allows the caller to care for certain type of errors and delegate the others to its own caller. With the current error type in Go, what would you do? parse the error message?