Earlier quoted context omitted.
I've always liked the Haskell approach of using a monad like Maybe or Either. Maybe is a special case where rather than having an error you have a null--perfect for functions like indexOf--but since it is isomorphic to Either (), all my points apply to both. The most important point is that in Haskell these errors are reified as first-class types. So the type `Either err val` is just like Go's method of returning eit…
Good writeup. Haskell actually does have an Error type class and ErrorT monad transformer for more fine-grained error handling. Maybe gives you binary error handling, it either fails (Nothing) or succeeds (Just). Either gives you "stringly-typed" errors which is sometimes a good choice. http://hackage.haskell.org/packages/archive/mtl/1.1.0.2/doc/...
Either doesn't have to be "stringly typed" per se thanks to sum types. You can write a type like:
data ErrorType = SomeError
| OtherError String
| ...
The compiler can now check that you handle all possible errors and will give you a warning if you don't, so it's strictly better than using strings.Coincidentally, this is one place where some sort of sub-typing would be nice, I think. This sort of type would be perfect using OCaml's polymorphic variants because then you could share different error cases around while specifying a very specific type for each computation.