In the GO 1 thread, some people have requested a built in error interface. I wanted to discuss some areas where having a built in error interface would make development easier.
Idiomatic GO (IMO) is succint, without sacrificing precision or introducing ambuiguity. You see this in the :=, lack of semicolons, multiple returns, implied return result (named return values), etc. It also promotes practices to reduce bugs (e.g. all declared variables must be used, all imports must be used, etc.)
There are 2 areas that I have wished special consideration to an error interface type were given:
- Ignored errors
- Chaining Commands
PS: I realize that the error interface method may have to be distinguishable (so ErrorString() instead of String()).
Ignoring errors
From reading the threads and in practice, a major culprit of programmer errors which are not handled are from programmers silently ignoring error return values of methods. For people coming from newer languages with runtime exception, they can afford to ignore errors (and typically do) knowing that the runtime would "panic" instead of proceeding if they ignored the error. In GO, these ignored errors are hard to track, and require programmer discipline to always check error return values and handle them before proceeding.
The compiler can help in the most common situation.
- If a function has the last return value be an error, then that must be assigned to a variable (or _ to ignore it). Else the compiler fails.
For example, for func A() os.Error, the following calls:
_ = A() //compiles
err := A() //compiles
A() // compilation fails
Chaining Commands
Currently, I have situations which would be ideal candidates for chaining. However, for those functions, there's a chance there could have an error. To accomodate, my only options seem to be to panic, so that they can still be chained. This is a bad solution, as callers now have to recover(...) when calling these functions.
It would be nice if the compiler supported the following:
- A set of methods can be chained if they each return two return values: 1. the same type that the method is defined on 2. an error type.
- When chained, the first error which is not nil breaks the chain.
E.g.
func (A) M1(...) A error
func (A) M2(...) A error
func NewA() A error
A, err := NewA().M1().M2() // err may be got from call to M1 or M2. Programmer realizes this.
...
For both of these, the error interface has to be known by the language, or at least by the compiler, and treated specially. This may make a case for a built-in type.