| name | griesemer-precise-go |
| description | Write Go code in the style of Robert Griesemer, co-creator of Go. Emphasizes clean syntax, precise semantics, and well-defined type system behavior. Use when designing APIs, type hierarchies, or code that requires precise specification. |
| tags | generics, type-parameters, interfaces, compiler, language-design, type-system, constraints |
Robert Griesemer Style Guide
Overview
Robert Griesemer co-created Go and was the primary designer of Go's generics. He previously worked on the V8 JavaScript engine and the Java HotSpot VM. His focus: precise semantics, clean syntax, and type system clarity.
Core Philosophy
"The language should help you think clearly."
"Every feature adds complexity. Is the complexity worth it?"
Griesemer values precision and clarity. Go's spec is remarkably small and clear because every construct has well-defined semantics.
Design Principles
-
Precise Semantics: Every language construct has exactly one meaning.
-
Orthogonal Features: Features should combine predictably.
-
No Surprises: Behavior should be obvious from reading the code.
-
Spec-Driven: If it's not in the spec, it's not guaranteed.
When Writing Code
Always
- Understand the exact semantics of operations
- Use types to express constraints
- Make nil behavior explicit and safe
- Write code that matches Go's spec, not implementation details
- Use generics when type safety improves clarity
- Define clear type constraints
Never
- Rely on unspecified behavior
- Assume implementation details (memory layout, etc.)
- Create ambiguous APIs
- Use empty interface when a constraint works
- Ignore the distinction between value and pointer receivers
Prefer
- Explicit type constraints over
any
- Named types for domain concepts
- Method receivers that match semantics (value vs pointer)
- Clear zero values
Code Patterns
Generics Done Right (Go 1.18+)
func Max(a, b interface{}) interface{} {
switch v := a.(type) {
case int:
if v > b.(int) { return v }
return b
}
panic("unsupported type")
}
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64 | ~string
}
func Max[T Ordered](a, b T) T {
if a > b {
return a
}
return b
}
result := Max(3, 5)
result := Max(3.14, 2.71)
Precise Type Constraints
type Stringer interface {
String() string
}
type Integer interface {
~int | ~int64
}
type Named[T any] interface {
*T
GetName() string
}
type OrderedStringer interface {
Ordered
Stringer
}
type Set[T comparable] struct {
items map[T]struct{}
}
func (s *Set[T]) Add(item T) {
if s.items == nil {
s.items = make(map[T]struct{})
}
s.items[item] = struct{}{}
}
func (s *Set[T]) Contains(item T) bool {
_, ok := s.items[item]
return ok
}
Value vs Pointer Semantics
type Point struct {
X, Y float64
}
func (p Point) Distance(q Point) float64 {
dx := p.X - q.X
dy := p.Y - q.Y
return math.Sqrt(dx*dx + dy*dy)
}
func (p *Point) Scale(factor float64) {
p.X *= factor
p.Y *= factor
}
type Buffer struct {
data []byte
}
func (b *Buffer) Write(p []byte) (int, error) {
b.data = append(b.data, p...)
return len(p), nil
}
func (b *Buffer) String() string {
return string(b.data)
}
Safe Nil Handling
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
if s == nil {
panic("nil stack")
}
s.items = append(s.items, item)
}
func (s *Stack[T]) Len() int {
if s == nil {
return 0
}
return len(s.items)
}
type UserID int64
type OrderID int64
func GetOrder(uid UserID, oid OrderID) (*Order, error) {
}
Precise Interface Design
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
type Container[T any] interface {
Add(T)
Remove(T) bool
Contains(T) bool
Len() int
}
Mental Model
Griesemer designs by asking:
- What does the spec say? Not the implementation—the specification.
- Is this unambiguous? Can two people read this differently?
- What are the edge cases? nil, zero values, overflow?
- Is the type constraint minimal? Don't over-constrain.
Spec-Level Thinking
| Feature | Spec Guarantee |
|---|
| Map iteration | Random order |
| Goroutine scheduling | Unspecified |
| Struct layout | Unspecified |
| String indexing | Bytes, not runes |
| Interface nil | nil interface ≠ interface holding nil |
Write code that works regardless of implementation details.