http://play.golang.org/p/9J46QRHul1
They presumably would like to force you to use the return value if it is of type error.
http://play.golang.org/p/9J46QRHul1
They presumably would like to force you to use the return value if it is of type error.
On a side note, does any programming languages force you to use the return value of every function call?
I probably /should/ get into the habit of writing error-handling code at the same time as writing the main-path code, but for someone who's just started learning the language and just wants to see what works, I find it really frustrating >_<
blah, err := foo(...)
if err != nil {
return nil, err
}
and it's sister: blah, err := foo(wibble)
if err != nil {
return nil, errors.New("foo error with blah due to: " + wibble)
}
After a while I got to like passing errors carefully back up the call stack , cleaning them up, rewriting them and making them more useful.My Go programs have far better (more detailed & relevant) error messages than any of my other code.
Yes, we all know how good humans are at work which no computer could ever do such as repetitive output of pointless generic boilerplate.
An exception and line-number (and a call-stack dump) is great for a developer, but a good textual error message is needed for a real user.
The first pattern does not do that. The second one is still mostly pointless generic boilerplate:
blah, err :=
if err != nil {
return nil, errors.New()
}
is all boilerplate, only two parts are not: the call itself and the error message.> An exception and line-number (and a call-stack dump) is great for a developer, but a good textual error message is needed for a real user.
1. having exceptions doesn't preclude handling them and writing user-readable error messages
2. exceptions are not the only alternative to C-style error handling
* the Haskell/ML statically typed approach, error possibility is type-encoded through an Option or Either type; even in cases where it is possible to implicitly ignore return values[0] the compiler will warn or error; the standard library provides high-level operations to pipeline results (build a pipeline of operations which will only transform non-erroneous results, and will let errorneous ones go through)
* the Erlang dynamically typed approach which makes use of tagged pattern matching to make value assertions trivial. It is not shorter than the Go version when fully handling things, but assertion can be used to fault processes during development or when in-process user-visible reporting is irrelevant (fairly common in erlang) yet remain easy to find and replace with more involved handling if needs be
[0] because haskell strives for purity, ignoring return values in non-monadic code makes very little sense and I'm not sure it's possible at all short of unsafe* functions. It is possible in monadic code (e.g. do blocks)
_, err := somethingThatFails(arg)
if err != nil {
return fmt.Errorf("failed with arg=%v, %v", arg, err)
}
Now the use for this is not obvious from this toy example, but having a `printf`-like function that produces error is great to return errors with more context.The difference from your example is that the info in `err` is not lost when passed up.
(I just picked (and cleaned up) the first piece of simple error code that I thought would be easy to use.)
if _, err := somethingThatFails(arg); err != nil {
return fmt.Errorf("failed with arg=%v, %v", arg, err)
}Well, you can always assign the error code to '_', and then just grep for those later. Or you can take the 10 seconds and just add the code to return the error as sambeau suggests.
func foo() error {
handleErr = func(err error) bool {
if err != nil {
log.Println(err)
// do other stuff
return true
}
return false
}
err := bar()
if handleErr(err) { return err }
}
It's nice and concise.I would like to implement this feature in Rust as well, as it would have saved me hours of debugging a couple of times.
GHC can also do so optionally (with -fwarn-unused-do-bind) (and I'm unsure there even is a way to ignore return values outside of do blocks)