leighmcculloch/gochecknoglobals

Suggestion for sync.Once-based exception and pattern recommendation?

Opened this issue · 0 comments

daroot commented

There are a number of a issues open and past related to exceptions for patterns where Go's lack of ability to do const for many classes of pre-initialized values such as maps, slices, funcs returning "constant" values like regexp.MustCompile, strings.Replacer, template.Must, etc. This includes #8, #23, #33, #41, and #42 among others.

One suggestion brought up in a few of these is to use a function at the module level that returns the "constant" value, but that can be expensive if the "constant" is frequently referenced and/or expensive to initialize.

Go 1.21 introduced a set of new utility functions in sync that wrap a sync.Once with in a closure to avoid recalculating the most common patterns of a one or two value return (sync.OnceValue, sync.OnceValues). Even in pre-1.21 Go, these functions are trivially replicable in about 20 lines of code.

Example:

var magicIntSlice = sync.OnceValue(func() []int { return []int{1, 2, 3} })

var replacer = sync.OnceValue(func() *strings.Replacer {
    return strings.NewReplacer(
        "-", "_",
        ".", "_",
        "/", "_",
    )
})

func UseConstSlice() {
   for i, val := range magicIntSlice() {
       fmt.Prinf("Hello magic value number %d is %d\n", i,  val)
   }
}

func DoReplaceThings(s string) string {
    return replacer().Replace(strings.ToUpper(s))
}

If there were an exception for variables of type sync.Once or the result of a sync.Once* function, plus a FAQ in the README suggesting this pattern, that would be an easy way to wrap all of these existing use cases and most future ones without adding individual exceptions for every const-like function or value. Since sync.Onc is idempotent and immutable once called, and fairly high performance, these seems like a natural way to build a pattern that represents an "acceptable" way to handle global state in the face of Go's lack of support for const in these situations.

Does this seem reasonable?