An unordered list of things I miss in Go
Nullability, nil, and type safety
- Strong push for explicit nullability types: compiler-enforced non-null refs (Rust
Option, C# nullable refs, Kotlin-style) are seen as a major safety win; dereferencing nil should not compile. - Counterpoint: Go’s design favors simple types and explicit error handling over a richer type system. Many accept nil as a trade-off; some argue nullability adds complexity and isn’t aligned with Go’s philosophy.
- Practical pain points: modeling DB columns, JSON “absent vs null vs zero value”, and unsafe
a.b.cchains. Workarounds include pointer-as-optional,Null[T]/Optionalwrappers, orsql.Null*, all with downsides. - Debate whether Go could ever retrofit nullability or sum types without breaking compatibility; some think nullability is easier than full unions, others doubt either will happen.
Map iteration order, randomness, and ordered maps
- Go maps randomize both hash seeding and start offset on each iteration. This is justified as:
- Hash-DoS mitigation.
- Enforcing the spec’s “unordered” promise and smoking out code that accidentally depends on order.
- Critics find per-iteration randomization surprising and harmful to reproducibility, debugging, and simple tasks like printing stable CLI help output.
- Comparisons: Python dicts preserve insertion order by design; Rust
HashMaphas per-map seeding but deterministic iteration; Java offersLinkedHashMapandTreeMap. - Strong subthread on terminology: unordered vs ordered-by-insertion vs sorted-by-key; hash maps vs trees; linked vs index-based ordered maps.
- Some want an ordered map (insertion-ordered hash) in Go’s stdlib; others say:
- If you need consistent order, sort keys (
slices.Sorted(maps.Keys(m))) or use a tree/other structure. - Ordered hash maps add overhead and ambiguous performance expectations.
- If you need consistent order, sort keys (
Default/named arguments and functional options
- Lack of default/named args is viewed by some as a feature: it forces API designers to think, and you can use wrapper functions.
- Others miss them for readability, especially around multiple bools or rarely-changed parameters; they cite Python and C# as more ergonomic.
- Functional-options pattern is a common Go workaround but criticized as:
- Verbose for general functions.
- Awkward when implemented via closures (no equality, hard for middleware/testing).
- Better when using typed or interface-based options.
Error handling ergonomics
- Many dislike repetitive
if err != nil { return ... }and want a?-style operator or automatic propagation. - Others embrace explicit error returns as core to Go, using helper
must()/must1()withpanicfor scripts or debugging. panic/recoverare noted as Go’s de facto exceptions, but mixing them witherroris seen as confusing in serious code.
Go’s philosophy vs feature wishlists
- One camp views omissions (nullability, enums, sum types, ordered maps, default params) as necessary constraints that keep Go simple and maintainable.
- Another sees Go as dated: they want richer type systems, sum types, better null handling, enums, and more ergonomic syntax; some look to Borgo, Rust, C#, or Swift as “Go but with modern features.”