You largely missed the point of my post. I was showing that Go values simplicity and consistency. The examples I used to illustrate that were exactly that: examples. They were not a list of features that were novel to Go, as you seem to have interpreted.
> Go the language is surprisingly complex and error prone compared to other GC languages because of its decision to allow explicit references.
It's true that having value types in addition to reference types (while other GC languages often only have reference types) adds some complexity to the language, it's not much and it's still much less complex and error prone than other GC languages. Also, C# has value types and Java desperately wants them, so I think it's pretty clear that they're worth the extra bit of complexity.
> This adds an extra layer of semantics to nearly every aspect of the language.
I don't think this is meaningfully true. You have to think about whether a thing is a value or a reference type. This is exactly one bit of additional complexity.
> Slices and arrays are another complicated area of the language, with gotchas like append sometimes modifying the original array, sometimes not.
Slices are actually quite simple, but people run into issues because they expect them to behave exactly like Python lists or JavaScript arrays. Slices are views into an underlying array, and appending to a slice always modifies the backing array; however, if the append causes a grow, then the backing array is now a different array than the original. Of course, your point stands in that this difference can be frustrating and that frustration is a real cost--but you run into that cost once or twice and you update your understanding and rarely encounter it again.
> Regarding splits, you still have that in Go as well - do you use goroutines as coroutines, sending copies of objects through channels? Or do you use them as threads, with shared memory and locking? Do you use the testing package as is, with its lack of any user-friendly asserts? Or do you pick up an assertion library? Do you use raw http,or something la Gorilla? Sql or some ORM? Do you log to stdout, or do you pick up a logging library?
I never claimed Go makes every decision for you, only that there are fewer decisions and the happy path is more obvious. You always use goroutines as threads and whether you use channels or locks is a design question (different use cases). The standard testing library is the happy path. You can add on an assert library if you really need it (although you probably don't). Similarly you use the raw HTTP library until you really need something more (you probably don't). Stdlib database/sql package or ORM? Again, database/sql until you need an ORM (again, you probably don't). Standard library logging package or a logging library? Again, you use the stdlib (happy path) until your requirements outgrow it. Notice the pattern?
> Regarding gofmt, I personally can't understand the passion some people have for enforcing a common style.
It avoids wasting time in nitpicky style conversations in code review and makes things easier to read. You're welcome to your opinion, but that's the rationale.
> Regarding build tools, Go is hardly unique among modern languages in having built-in tooling for that.
I didn't claim otherwise, only that Go's standard build tool is yet another example of simplicity and consistency. And many languages don't have a standard built-in tool, and the ones that do are often complex. The only language with a nicer build tool IMO is Rust, and like everything Rust vs Go, the Rust build tool prefers pragmatic complexity to simplicity (a philosophical difference that I can respect).
> Even then, if you have any other build artifacts you may find you need to reach for something other than Go's tooling. By comparison, Maven can easily handle a Java+minor bits-in-other-languages project out-of-the-box.
I don't see why every language should have a build tool that can build it + small bits of other languages. A build tool should build that language well, and extend it for bigger projects using a wrapper tool like Make or Bazel depending on use case. Unix philosophy and all that.
> Not to mention that Go is probably the only language in any kind of popular use today that doesn't have a built-in way to interface with C code (you need to use a separate compiler if you want that!).
Every language (even C++) needs another compiler to compile C code before it can be called into. And once it's compiled, it's no more difficult to call into it from Go than from Java or C# or Python or etc. It's also often easier, since you can use C values directly in Go without needing to write shims (e.g., PyObject shims). That said, like all GC languages, it's fundamentally hard to correctly manage ownership for references across the C/$LANG boundary.