This idea can also be explored in the Go programming language. Go has an error type, not exceptions, but error checking famously can be rather verbose.
Two cases to consider come to mind. First, the common pattern
result, err := SomeFunc()
if err != nil {
return err
}
Here the code is just passing along the error to the caller, unchanged.
Second, signaling errors ab initio
result := // some calculation or behavior
if result != expected
return fmt.Errorf("An error happened. Expected %v, go %v", expected, result)
In the first case, the discussions around whether or not to throw custom exceptions applies analogously: should you wrap the error or not?
The second case, I argue, is always wrong. The error is "stringly typed", and can be examined and read by a person, but that's it. The correct way is to define an error type meaningful for the context. Errors in Go are type implementing the error interface
type error interface {
Error() string
}
therefore, an error should be a type relevant or the context. A useful starting point looks something like
type DomainError struct {
Code DomainErrorCode
Message string
Details []DomainType
}
func (d DomainError) Error() string {
return Message
}
then code can look like
// some work
if result != expected {
return DomainError {
Status: AnErrorCode
Message: fmt.Sprintf("Error %v. Expected %v, go %v", AnErrorCode expected, result)
Details: []DomainType{ expected, result }
}
}
And the caller gets back a type providing useful information.