Is Append(s, X) Without Assignment A Classic
Fast recall
Quick revision
Core answer
Practical understanding of Append And Growth.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
The bug hides because it's intermittent: append sometimes works without assignment. While capacity remains, the returned header equals the original — same pointer, same array — so append(s, x) without capturing the result still leaves the element visible through s. The code passes its tests.
Then an input one element longer arrives, capacity is exceeded, append allocates a new array, and the element goes into the copy that's returned — which is discarded. The caller's s still views the old array. No error, no panic: the element just doesn't exist as far as any reader of s can tell.
That silence is what makes it pernicious. Go's compiler won't flag it — the call is legal — and the failure only appears under the capacity-exceeded branch. The guard is purely idiomatic: always write s = append(s, x), even when you're sure capacity remains, because 'sure' is what the bug waits for.
Is Append(s, X) Without Assignment A Classic
Direct Answer
When growth occurs, the new header lives only in the return value. The original s still points at the old array — the appended element is lost to the caller.
Deep Dive & Architecture
The two-timeline trace makes the failure concrete:
func addTo(data []int, items ...int) {
for _, it := range items {
data = append(data, it) // correct: reassigns
}
_ = data // if this were the bug version, data's growth would be local-only
}
// the bug shape:
s := make([]int, 0, 2)
append(s, 1) // fits in cap — works, s sees 1 through... nothing
append(s, 2) // fits — s would see [1 2] if reassigned
append(s, 3) // cap exceeded — allocates, but the header is DISCARDED
fmt.Println(len(s)) // 0 — none of it was ever captured
The prints show the whole mechanism: append always returns the current truth, and the caller's variable only updates by assignment. The runtime never reaches back into your variable — that's what passing by value means for the header.
This is why linters like golangci-lint grew an appendAssign check — the bug is invisible to the compiler, common in quick code, and only detectable by recognizing the discarded-result shape. Know the idiom before you need the linter.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Append And Growth, and when would you use it?
- When would you use Append And Growth in a real project?
- What is a common mistake when using Append And Growth?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.