home / skills / copyleftdev / sk1llz / griesemer
This skill helps you design Go APIs with precise semantics and clean syntax inspired by Griesemer, improving type safety and readability.
npx playbooks add skill copyleftdev/sk1llz --skill griesemerReview the files below or copy the command above to add this skill to your agents.
---
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.
---
# 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
1. **Precise Semantics**: Every language construct has exactly one meaning.
2. **Orthogonal Features**: Features should combine predictably.
3. **No Surprises**: Behavior should be obvious from reading the code.
4. **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+)
```go
// BAD: Empty interface loses type safety
func Max(a, b interface{}) interface{} {
// runtime type assertion needed
switch v := a.(type) {
case int:
if v > b.(int) { return v }
return b
// ... repeat for every type
}
panic("unsupported type")
}
// GOOD: Type constraints preserve safety
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
}
// Usage: type-safe, no assertions
result := Max(3, 5) // int
result := Max(3.14, 2.71) // float64
```
### Precise Type Constraints
```go
// Constraint: any type with these methods
type Stringer interface {
String() string
}
// Constraint: underlying type is int
type Integer interface {
~int | ~int64
}
// Constraint: must be pointer to struct with Name field
type Named[T any] interface {
*T
GetName() string
}
// Combining constraints
type OrderedStringer interface {
Ordered
Stringer
}
// Generic data structure with constraint
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
```go
// Value receiver: method doesn't modify, type is small
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)
}
// Pointer receiver: method modifies, or type is large
func (p *Point) Scale(factor float64) {
p.X *= factor
p.Y *= factor
}
// IMPORTANT: Be consistent within a type
// If ANY method needs pointer receiver, use pointer for ALL
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 { // Also pointer, for consistency
return string(b.data)
}
```
### Safe Nil Handling
```go
// Make nil receiver safe
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
if s == nil {
panic("nil stack") // Or return error
}
s.items = append(s.items, item)
}
func (s *Stack[T]) Len() int {
if s == nil {
return 0 // Safe: nil stack has zero length
}
return len(s.items)
}
// Named types for clarity
type UserID int64
type OrderID int64
// Now these can't be accidentally swapped
func GetOrder(uid UserID, oid OrderID) (*Order, error) {
// ...
}
```
### Precise Interface Design
```go
// Small, precise interfaces
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
}
// Compose precisely
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
// Generic interface with type parameter
type Container[T any] interface {
Add(T)
Remove(T) bool
Contains(T) bool
Len() int
}
```
## Mental Model
Griesemer designs by asking:
1. **What does the spec say?** Not the implementation—the specification.
2. **Is this unambiguous?** Can two people read this differently?
3. **What are the edge cases?** nil, zero values, overflow?
4. **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.
This skill teaches how to write Go code in the style of Robert Griesemer, emphasizing precise semantics, clear syntax, and well-defined type behavior. It focuses on API and type design, generics, and safe nil/value semantics to produce unambiguous, spec-driven code. Use it to align implementations with the mental model behind Go's language design.
The skill inspects code patterns and suggests rewrites that favor explicit type constraints, small precise interfaces, and consistent receiver choices. It recommends generics when they improve type safety, enforces safe nil handling, and highlights places that rely on unspecified implementation details. Suggestions are framed around spec-level thinking and concrete transformations you can apply immediately.
When should I prefer generics over interfaces?
Prefer generics when type constraints preserve compile-time safety and eliminate runtime assertions. Use small interfaces when the abstraction is behavioral rather than structural.
How do I decide between value and pointer receivers?
Use value receivers for small, immutable-like types and methods that don’t modify state. Use pointer receivers when methods mutate state or the type is large. Be consistent across all methods for a type.