Do I understand correctly that "last return value is error" is purely convention and there is no formal error handling in current go?
My instinct is to leverage the 'else' keyword along with the notion of a "stock error whose return list's last element is type error with value != nil.
func not_stock() (int, interface{})
func stock() error
func stock() (int, error, string, float, error, error, error)
func not_stock() (error, error, error, int)
func stock() (error, error)
Any other type of error handling can still be handled as the user wishes, stock errors simply provide syntax to lean into, and that syntax would be:
[ <assignment> ] <call expr> ast.ELSE <block statement>
e.g.
file, err := io.Open(file) else {
return nil, err
}
fh.Close() else {
panic("close call failed")
}
Equivalent to:
file, err := io.Open(file)
if err != nil {
return nil, err
}
if err := fh.Close(); err != nil {
panic("close call failed")
}
One of the current nuisances of error handling is that it can break the clean flow of variable assignments, forcing you to add separate declarations or scopes. Given a function
func NewStruct() (s *Struct, sz int, err error)
you typically have two very different lifespans for the return values
s, sz, err := NewStruct()
if err != nil { // last reference to err in function
vs
if s, sz, err := NewStruct(); err != nil {
panic(err)
} else {
// to access s and sz
}
or
var (
s *Struct
sz int
err error // but literally only for one line
)
if s, sz, err = NewStruct(); err != nil {
panic(err)
}
Using the else construct always allows the shorter form, which is at least consistent:
// not a sub-clause so s, sz and err introduced in current scope level.
s, sz, err := NewStruct() else {
panic(err)
}
The fly in the ointment here is ... where does the error go if you don't mention it?
fh.Close() else {
panic(?what?)
}
the lazy option would be `_`
fh.Close() else {
fmt.Errorf("unexpected close failure: %s", _)
err := _
panic(err)
}
But I think we can avoid the path of perl, and simply require capture if you want the value surfaced.
err := fh.Close() else {
panic(err)
}