go-value-pointer-semantics

Installation
SKILL.md

Go Value/Pointer Semantics

Choosing value vs. pointer semantics is one of the most consequential design decisions in Go, and it is implicit in nearly every type, method, and function you write. This skill encodes a single rule and the decision procedure for applying it.

The core rule

Pick a semantic per type at declaration time, then make every method, parameter, and return value for that type respect it. A type is value-semantic or pointer-semantic; it is never both. APIs conform to the type's semantic — they do not get to change it.

Why this matters: a reader builds a mental model of the code by tracking how data flows. If a type is copied in one function and shared by pointer in the next, that model breaks, and bugs, data races, and aliasing surprises slip in unseen. Consistency is what keeps the model intact as the codebase and team grow. Inconsistent semantics for a single type is the thing to flag in review.

The trade-off being managed (Bill Kennedy's framing): value semantics keep data on the stack and reduce GC pressure, but require copies to be stored and tracked; pointer semantics keep one shared copy, but push data to the heap and add GC pressure. Neither is "better" — consistency is.

Decision procedure

Decide the semantic when you declare the type, using this order:

  1. Built-in types — numeric, string, bool. → Value semantics. Don't take pointers to share them without a strong, specific reason.

  2. Reference types — slice, map, channel, func, interface (write any, not interface{}). → Value semantics. These already hold an internal pointer to a shared backing structure, so passing them by value is cheap and keeps the header on the stack. Don't use *[]T, *map[K]V, etc. (The main exception: handing a slice/map into an Unmarshal call.) This extends to modern additions: iterator types (iter.Seq[T], iter.Seq2[K,V]) are func values and are value-semantic, and a generic type parameter carries the semantic of the type it resolves to — a []T or func(T) parameter is still value-semantic regardless of T.

Installs
2
First Seen
Jun 23, 2026
go-value-pointer-semantics — ethangardner/agent-skills