> There aren't any colossal Go codebases yet, but so far things are looking promising.
Not really. 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 packages all of that in a less regular syntax just in case there was any chance to get a good language out of the previous clusterfuck.
Nullable pointers and shared state reflect the way the machine actually works. If you regard these design decisions as mistakes, then Go clearly isn't the language for you.
(also, which language is Go less regular than? Lisp?)
Go strikes a middle ground between low-level and high-level in some awkward ways. It wouldn't be hard to use e.g. nullable types or option types to outlaw null pointer exceptions without restricting the set of possible programs, and with stronger static guarantees of correctness. On the other hand, Go also has mandatory garbage collection, which emphatically does not reflect the underlying machine and also restricts its usefulness in certain situations.
w/r/t regularity: most of the functional programming languages (e.g. ML, Haskell sans GHC extensions, various Lisps) are incredibly regular, especially in the semantic sense of providing a few semantically simple features and milking them for all they're worth. Go has quite a few special cases (e.g. the make versus new distinction, the iota keyword) and some odd omissions (e.g. simulating union types involves what I perceive as interface trickery; const only allows numbers or strings as values.) Coming from C++, Java, &c, Go seems incredibly regular—the lack of OOP goes a long way towards keeping it simple—but it's not a simple language except in the context of "modern, Algol-derived applications languages." Which it is an improvement on, but it's not regular in the strict sense.
> 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.
Not really. 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 packages all of that in a less regular syntax just in case there was any chance to get a good language out of the previous clusterfuck.