Thoughts on Go vs. Rust vs. Zig
Rust complexity and ergonomics
- Some see Rust as conceptually dense (traits, lifetimes, async, Pin, unsafe), “like learning to program again.” Others say 95% of real-world Rust is much simpler than stdlib/compiler examples and quite approachable after the initial hump.
- Difficulty is often linked to trying to write OO-style or C/C++-style code; people who approach “Rust as Rust” reportedly have fewer problems.
- Immutability and move semantics spark confusion (fear of “out-of-date” copies), but defenders highlight benefits: fewer hidden mutations, safer concurrency, and compile-time guarantees around ownership and aliasing.
- Rust’s type system and Result/Option are praised for encoding invariants and forcing explicit handling, but many find error handling ergonomically messy (thiserror/anyhow/enums/non_exhaustive, conflicting “best practices”).
Error handling: Go vs Rust vs Zig
- Go: explicit
if err != nilis lauded for readability and making failure points obvious, but criticized as verbose and easy to misuse (unwrapped errors, shadowed variables, stringly-typed matching). - Rust:
?and typed errors enable precise, exhaustively handled failures, but can be verbose to define; some complain the ecosystem lacks a single “canonical” pattern. - Zig: error unions plus
tryseen as cleaner than Go’s multi-return, but still low-level; closer to explicit Result-style handling.
Globals, concurrency, and safety
- Rust deliberately makes mutable globals awkward (require unsafe or Mutex/atomics/thread-local), which some see as a feature to discourage a major bug source. Others argue this undermines simplicity for legitimate global use (logging, pools, caches).
- Rust’s Send/Sync and borrow checker aim to make data races impossible in safe code; race conditions and deadlocks remain possible but more localized.
- Go’s goroutines and channels are widely praised for ease of concurrent programming, though critics point to lack of structured concurrency and subtle footguns (context cancellation, Timer semantics, slice aliasing).
Zig’s philosophy and trade-offs
- Zig emphasizes explicit memory management and allocator-passing; all allocations are conceptually fallible, which appeals for embedded and tight-resource systems.
- It rejects RAII and heavy abstractions; fans like the “data-oriented,” simple mental model and low ceremony at scale, detractors see extra manual legwork and potential for UB when checks are disabled in release.
- Syntax and anti-RAII rhetoric divide people; some find it refreshingly small and direct, others see unnecessary divergence from established conventions.
Go’s niche and limitations
- Valued for “fits in your head” simplicity, strong stdlib, quick delivery with few dependencies, and a very approachable concurrency story.
- Criticisms center on lack of enums/sum types, boilerplate error handling, weaker static guarantees, and a type system viewed as too limited compared to Rust or ML-family languages.