When would you use Method Sets in a real project
Fast recall
Quick revision
Core answer
Practical understanding of Method Sets.
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 two receiver declarations and what each one means:
func (u User) Greet() string { return "hi " + u.Name } // value: works on a copy
func (u *User) Inc() { u.Age++ } // pointer: works on the originalExecuted asymmetry: after p := &u; p.Inc(), the original u.Age changed (verified: 30 → 31). A Greet on u or p — same result, no visible difference, because Greet doesn't mutate.
When to choose which — the decision list, in order:
- 1Mutate the receiver? Pointer. The only way the change survives the call.
- 2Struct large? Pointer. A value receiver copies the whole struct on every call — an 8-field struct with a map and slices copies three words (headers), but a 64-field data struct copying per call is real cost. The runtime number to know: value receivers pass by copy — cost proportional to struct size; pointers pass one word.
- 3Consistency: a type with ONE pointer method should make them all pointer — mixing receiver kinds makes the method-set behavior confusing (some methods in the interface-satisfying set, some not).
- 4Value receivers for: small structs, immutable-by-design types, methods on maps/slices/funcs — where the type itself is a reference and copying is trivial.
The trap the receiver kind sets: value receivers satisfy interfaces from BOTH User and *User; pointer receivers only from *User — the method-set rule from the previous question. So a type whose mutation methods are pointer-receiver can't be stored by value in interfaces needing those methods — an interface design consequence hiding in a receiver choice.
When would you use Method Sets in a real project
Direct Answer
Value receiver (u User): gets a COPY — mutations don't escape. Pointer receiver (u *User): gets the address — mutations persist. Rule of thumb: pointer when you mutate, when the struct is large, or for consistency with other methods; value for small immutable data.
Deep Dive & Architecture
The copy mechanics, one layer down: a value receiver method call compiles to the method receiving a fresh copy of the struct — stack storage for the parameter, contents copied at call time. The copy is shallow — reference-typed fields (slices, maps, pointers) copy their HEADERS, pointing at the same underlying data. So a value receiver CAN mutate a slice's elements (u.Tags[0] = "x" writes through the shared array) but can't replace the field itself (u.Tags = nil changes only the copy's header). That half-mutation is the most common value-receiver bug: the author thinks 'value = safe from mutation' and writes through an embedded reference — mutation escapes anyway.
The pointer receiver's dereference cost: negligible (one memory indirection) — and often NET CHEAPER than a large value copy. The performance folklore 'pointers are for big structs' has the direction right: the crossover is where the copy cost exceeds one indirection — for small structs (a few words), value receivers can actually be FASTER (no indirection, better locality, escape analysis can keep everything in registers).
The escape-analysis interaction nobody mentions: a pointer receiver means the receiver's address escapes into the method call — which can force heap allocation of the receiver variable if the method (or anything it calls) stores the pointer. A value receiver on a small struct stays stack-local more easily. 'All pointer receivers' as a style rule has a cost: it can quietly push allocations up in tight loops — one reason the standard library mixes deliberately (time.Time's methods are value receivers — small, immutable, allocation-conscious).
The receiver choice is also API documentation: a value receiver tells the caller 'calling this changes nothing on the original' — a contract the compiler enforces. Pointer receivers say 'this may modify' — readers check. That signal is why consistency matters beyond tidiness: a type with mixed receivers forces readers to check each method's kind, per call, to know what might change.
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 Method Sets, and when would you use it?
- How would you compare Method Sets with an alternative?
- What is a common mistake when using Method Sets?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.