Patterns: creation · 3 MIN READ
Singleton: once does not mean global mutable state
Understand one-instance intent and choose an explicit lifetime.
Understand one-instance intent and choose an explicit lifetime. Singleton controls access to one instance. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.
Creational pattern · A MAP OF THE IDEA
- Owner creates a once function
- First call constructs the value
- Later calls receive that same value
Useful when
- One owner needs lazy immutable initialization
- Creation should happen at most once
Watch out
- Global mutation hides coupling between tests
- Once is not a transient-error retry policy
Implementation & operation cost: Medium
Fit depends on the task
Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.
The design decision
Singleton controls access to one instance. Go can initialize once with sync.OnceValue, but a package-global mutable object hides dependencies and shares state across tests. Prefer one explicitly constructed application dependency unless unique identity is a genuine requirement.
A complete Go example
Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.
package main
import (
"fmt"
"sync"
)
type Config struct{ Region string }
func main() {
calls := 0
load := sync.OnceValue(func() *Config { calls++; return &Config{Region: "local"} })
a, b := load(), load()
fmt.Println(a == b, calls)
}
// Output:
// true 1
The closure creates one Config for its owner and returns the same pointer twice. OnceValue synchronizes initialization, not future mutation of Region. Keeping the owner local makes the lifetime visible and avoids a hidden process-wide dependency.
Tradeoffs and the simpler alternative
OnceValue caches a panic as well as a result; it is not a retry mechanism for transient startup failures. Separate immutable configuration from mutable clients, and inject the latter. Shared uniqueness can complicate parallel tests, shutdown and replacement.
TAKE THIS WITH YOU
Synchronizes creation but not later object mutation. OnceValue caches a panic as well as a result; it is not a retry mechanism for transient startup failures. Separate immutable configuration from mutable clients, and inject the latter. Shared uniqueness can complicate parallel tests, shutdown and replacement.
Check your understanding
Which statement best describes Singleton: once does not mean global mutable state?
Go to the source
Progress stays in this browser. No account needed.