> Go keeps all the old errors everybody should know are errors (nullable pointers, shared mutable state, raw types, ...) and then proceeds to add new ones,
And because of the absence of exceptions, Go forces you to deal with errors at the call site (see the number of times you see "ok, err = Foo(); if (err)..." which is not scalable to large scale software.
I left this specific point out, because I'm on the fence about it. I do think the C-style way of Go is a genuine mistake, but I also think when type systems are used to force the caller to know about what's happening but the language provides tool which let this be done in a non-absolutely-painful manner (à la haskell, with the `Either` type being used to report success/error, and pattern matching or monadic lifting letting users either act cleanly or propagate errors without being overly verbose and drowning their own code in explicit error propagation) it works rather well, and limits the amount of runtime surprises.
On the other hand, return-value-error-reporting does not give a way for deep callers (caller of the original API when the error happens 6 frames down the stack) to try and recover (instead of just bail out, or more generally customize the error recovery policy) the way condition systems do in Smalltalk, Common Lisp or Dylan.
And because of the absence of exceptions, Go forces you to deal with errors at the call site (see the number of times you see "ok, err = Foo(); if (err)..." which is not scalable to large scale software.