Why Go’s Error Handling, Defer, and Nil Design Feel Like Bad Ideas
The article critiques Go’s language design by highlighting unnecessary patterns such as overly broad error‑variable scopes, confusing nil semantics, cumbersome defer usage, hidden memory costs, and a lack of clear ownership, illustrating each point with concrete code examples and comparing alternatives in other languages.
Incorrect variable scope and forced errors
The author shows how Go forces developers to write repetitive error‑handling boilerplate, arguing that limiting a variable’s scope to just a few lines would improve readability. Example:
if err := foo(); err != nil {
return err
}Later code demonstrates how the same err variable can be unintentionally reused across multiple calls, leading to bugs and confusion.
bar, err := foo()
if err != nil { return err }
if err = foo2(); err != nil { return err }
// …The author questions why the language does not allow tighter scoping.
Two types of nil
A small program illustrates surprising equality results when comparing nil interfaces and pointers, emphasizing that Go’s handling of nil can be misleading.
package main
import "fmt"
type linterface{}
type S struct{}
func main() {
var il linterface{}
var s *S
fmt.Println(s, il)
fmt.Println(s == nil, il == nil, s == il) // true, true, false
il = S{}
fmt.Println(s, il)
fmt.Println(s == nil, il == nil, s == il) // true, false, true
}The confusion stems from Go’s lack of thoughtful design around nil.
It’s not portable
Adding conditional compilation comments at the top of files is criticized as a poor practice that hampers portability; the author likens it to “locking yourself in a room and never testing assumptions against reality.”
append without clear ownership
Examples show how appending to a slice via a subslice can produce unexpected results because the underlying array is shared:
package main
import "fmt"
func foo(a []string) {
a = append(a, "NIGHTMARE")
}
func main() {
a := []string{"hello", "world", "!"}
foo(a[:1])
fmt.Println(a) // [hello NIGHTMARE !]
}A second example demonstrates that the same operation can leave the original slice unchanged, highlighting the unintuitive ownership model.
package main
import "fmt"
func foo(a []string) {
a = append(a, "BACON", "THIS", "SHOULD", "WORK")
}
func main() {
a := []string{"hello", "world", "!"}
foo(a[:1])
fmt.Println(a) // [hello world !]
}defer is stupid
The author argues that Go’s defer mechanism forces developers to consult documentation for each resource, leading to error‑prone patterns such as double‑closing files or forgetting to defer when needed.
foo, err := myResource()
if err != nil { return err }
defer foo.Close()Similar boiler‑plate appears when writing to files, making code verbose and fragile.
Standard library swallows exceptions
Go claims to have no exceptions, yet the standard library often hides errors, forcing developers to write “exception‑safe” code without actual exception support. This leads to awkward patterns like unlocking mutexes with defer and worrying about panics leaving resources locked.
func (f *Foo) foo() {
f.mutex.Lock()
defer f.mutex.Unlock()
f.bar()
}Sometimes not UTF‑8
When arbitrary binary data is placed into a Go string, the runtime accepts it silently, which can cause data loss for non‑UTF‑8 filenames or content, a problem the author has experienced in backups.
Memory usage
Although memory is cheap, the author cares about it because services run on cloud instances where RAM is billed. Go’s garbage collector may retain more memory than expected; manual triggering with runtime.GC() is discouraged by the standard library, yet sometimes necessary.
runtime.GC()The author rewrote parts of a project in another language because newer Go versions consumed increasingly more memory.
Too many unnecessary things
The article concludes that many of Go’s design choices feel like “stupid” shortcuts that were not thoughtfully considered, comparing them to outdated scientific methods that ignore real‑world testing.
Author: 手扶托拉斯基 Reference: https://blog.habets.se/2022/08/Java-a-fractal-of-bad-experiments.html
Related reading:
Go、Python、Rust:我们该学习哪一款?
JetBrains 正在开发更高抽象的编程语言
十个最受欢迎的本地语言大模型
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
