Wouldn't it make more sense to have some sort of manager that receives information on an incoming channel, manages the state internally, and reports out on an outgoing channel?
Abstractly, if you somehow need a singleton object, this will be substantially faster if you need it frequently. And if you're careful to do all the other things you need to do in order to make this work and safe, as seen in the other messages in this post.
Practically, all the examples I've ever of why you'd ever want a singleton are indeed better done as a goroutine server over channels. Within the object you get an implicit lock by virtue of being the only goroutine ever to touch that stuff, and as long as you don't need this object to use more than one CPU total and the overhead of channels isn't a big deal, which again, describes the vast bulk of cases I've ever heard of that call for singletons, it's a better way to go.
And I'd note I've written a couple dozen different goroutine server things and a grand total of 0 'singletons', so... yeah.
If I had an immutable singleton object that was somehow very expensive to initialize, I might consider this approach. Not sure when that would come up but I'm sure it describes something.
A singleton is basically a global variable and those aren't really important to "shim" in Go. Object method calls are pretty much the same conceptually as message passing but when you actually need to synchronize as you point out goroutines and channels make things much simpler. I think what this post was going for wasn't "use singletons", it was "look at these interesting threading issues that arise and how we address them in (non idiomatic) Go"
There's more that needs to be done if the goal is "look at these interesting threading issues that arise and how we address them in (non idiomatic) Go", because the initialization described in the post is broken.
Shared-memory multithreading is hard. Golang does not do much to prevent you from shooting yourself in the foot here, as this post proves. So use the abstractions wherever possible. In this case, Once correctly performs the atomics, and naive double-checked locking doesn't.
Practically, all the examples I've ever of why you'd ever want a singleton are indeed better done as a goroutine server over channels. Within the object you get an implicit lock by virtue of being the only goroutine ever to touch that stuff, and as long as you don't need this object to use more than one CPU total and the overhead of channels isn't a big deal, which again, describes the vast bulk of cases I've ever heard of that call for singletons, it's a better way to go.
And I'd note I've written a couple dozen different goroutine server things and a grand total of 0 'singletons', so... yeah.
If I had an immutable singleton object that was somehow very expensive to initialize, I might consider this approach. Not sure when that would come up but I'm sure it describes something.