Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
daroot opened this issue Aug 16, 2023 · 0 comments
Open

Comments

@daroot
Copy link

daroot commented Aug 16, 2023

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant