Go: What we got right, what we got wrong

A retrospective by Go co-creator Rob Pike has reignited debate over what the language got right and wrong in its design and evolution. Commenters broadly credit Go with fast tooling, a strong standard library, simple concurrency primitives, and a deliberately small, stable core that made it a popular choice for servers and infrastructure. Criticisms focus on weak FFI and scientific‑computing support, the long delay and current limits of generics, pervasive nil/error pitfalls, package and versioning missteps, and a leadership style some see as dismissive of community needs, especially around error handling, REPLs, and time/crypto APIs.

Go’s intended niche and what it became

  • Designed at Google as a simpler, faster replacement for C++ for servers and “systems software” (in a broad sense: servers, networking, infrastructure), not for kernels or drivers.
  • Several commenters say Go ended up more as a “server / internet backend” and CLI language than a low‑level systems language.
  • Some argue it successfully displaced a lot of C++ and some Python in server/infrastructure work; others say it competes more with Java/C# than with C/C++/Rust.

Scientific computing, FFI, and HPC

  • Early Go team reportedly dismissed scientific/HPC use cases, REPLs, and scripting‑language integration; this is seen as a missed opportunity.
  • cgo and the gc compiler’s C call overhead are widely criticized; Go is viewed as having a weak FFI story, especially for scientific computing where C/Fortran interop is crucial.
  • Counterpoint: most scientific work is scripting in Python/R/Julia; Go, as a systems language, is not a natural fit anyway.

Concurrency and goroutines

  • Goroutines are described as user‑space “green threads” or M:N scheduling with stackful fibers on top of OS threads; good for high‑concurrency servers.
  • Some think Go oversold goroutines as novel; others see them as a practical, successful model despite being similar to older green‑thread systems.
  • This concurrency model complicates C FFI and influences runtime design (e.g., no code generation at runtime).

Error handling, panics, and nil

  • Error‑as‑values plus panics is one of the most contested areas:
    • Critics: verbose, repetitive if err != nil patterns, easy to accidentally swallow errors, two parallel mechanisms (errors vs panics) that don’t mesh cleanly, and painful nil handling (including interface vs concrete nil gotchas).
    • Defenders: explicit errors are simple and predictable, encourage handling, and avoid hidden control flow.
  • Nil pointers and lack of null‑safety are cited as major design mistakes; some tools (e.g., linters, nil analyzers) try to mitigate this.

Generics and type system

  • The long delay before adding generics is heavily debated:
    • Pro: waiting avoided flawed designs that would have been hard to fix later.
    • Con: launching without generics repeated old mistakes (e.g., Java pre‑generics), warped APIs, and forced workarounds (interface{} everywhere).
  • Current generics are seen as useful but incomplete (e.g., missing method‑level generics), and constrained by existing interface semantics.

Modules, packaging, and tooling

  • Early GOPATH/go get behavior and import‑by‑URL are criticized as naïve and overfitted to Google’s monorepo; community package managers grew in the gap.
  • Official modules and MVS are generally praised as a big improvement, though SIV (v2+), private repos, and SSH/git config remain pain points.
  • gofmt, unified tooling (go build/test/fmt), static binaries, and relatively fast compilation are widely seen as major strengths.

Community process and evolution

  • Some see Go leadership as too dismissive/slow on issues like generics, monotonic time, crypto updates, REPLs, and context usage.
  • Others praise the willingness to say “no”, keep the language small, and prioritize stability and tooling over rapid feature accretion.