Live data from Hacker News

Singleton Pattern in Go

marcio.io

61–70 of 76 posts

Re: Singleton Pattern in Go

#61
post #34

Coding Pro Tip: Instead of using the Singleton pattern, make one instance of your class at the start of your program and pass it around to its users. Singletons are really just as bad as global variables. Why? Because they are global variables.

Depending on what you are trying to implement - passing an extra variable everywhere is just creating noise (because potentially you have to have an extra parameter to EVERY function or method). I believe in KISS - everything should be as simple as possible but not simpler. Believe it or not there are valid uses for a Singleton which, many would agree, include a simple logging class [1]. One could argue that you coul…

> you have to have an extra parameter to EVERY function or method

Dependency injection provides a pretty good solution to this, potentially even for the logging use case. Classes (or code modules or whatever) only need to think about their direct dependencies, and indirect dependencies are handled naturally by the wiring code. In a well-written codebase using DI, you basically never need to write code that accepts an argument just so that it can pass that argument down to other code.

For example, if a class Foo deep in your program wants to use an interface called Logger for the first time, you just add a Logger as a field and pass the Logger into the Foo constructor in your wiring code. It's a little more ceremony than an import statement, but not by much, especially if you use a DI framework to do the wiring for you. Importantly, you don't need to make any changes to code that uses Foo.

An advantage to this approach is that it makes it easier to test usage of Logger (e.g. asserting that Foo logs an error in a particular situation). It also makes it easier to extend the Logger, like using a Logger wrapper that collects statistics on what was logged, without needing a special extensibility point in the Logger implementation.

That's not to say globals/singletons are always a bad idea. They tend to result in shorter code and they're easier to understand, and you can still test against them if you're willing to use mutable singletons (e.g. monkey patching in Python) or custom extensibility points. My main point is that, if you have a class that's useful in a wide variety of situations, there are other solutions than just "use a global" and "explicitly pass it around everywhere", and IMO dependency injection is one of the best options if you're writing serious code.

Re: Singleton Pattern in Go

#62

It's funny how you can take an obvious antipattern (global variables) and turn it into a pattern by giving it a cool new name like "Singleton". In this spirit, I propose "the ProgramCounterAmbulator" as a cool new name for "goto." Actually, gotos are usually less harmful than globals. At least they don't interfere with unit testing the way globals tend to.

No argument that Singletons make it difficult to unit test things but there are genuine cases where singletons are required: For instance, you don't want to end up creating multiple objects that read the configuration file, when one is enough. Or you certainly don't want to create too many objs that are heavy (like a cache that stores data heavy objects, or services, or god-objects (which are themselves an anti-patte…

Depends on what you mean by "singleton". If you define it loosely as "a type of which there is only one instance", fine, no problem -- of course those will exist. But if you define it as "globally-accessible mutable state", then the problems start. Usually, the "singleton pattern" is explicitly a technique for doing the latter.

> For instance, you don't want to end up creating multiple objects that read the configuration file, when one is enough.

Sure. But that doesn't mean the config file reader has to be globally-accessible. Instead, try allocating it on the stack in your main() function, then passing the object into each component that needs to see it. Better yet, only pass each component a sub-object(s) of the config which applies specifically to that component.

Now you have a bunch of useful benefits:

- Readability: You can clearly see and follow what components are affected by what parts of the config file.

- Testability: Unit tests can easily provide a test configuration.

- Maintainability: If some day you realize that you need to create two instances of some component and configure them differently, it's easy to do that without rewriting tons of code or introducing horrible "namespacing" hacks.

- Security: If your config file contains anything sensitive (say, database credentials), it's no longer the case that every damned module in the whole system has the ability to read those secrets. In fact, if your language is memory-safe and bans mutable global state, you can trivially sandbox any piece of code by simply not passing it references to anything it shouldn't be able to access. (This is called "capability-based security" or "object capabilities", and it works.)

Extended argument (which I wrote many years ago...):

http://www.object-oriented-security.org/lets-argue/singleton...

Re: Singleton Pattern in Go

#63
post #56

Coding Pro Tip: Instead of using the Singleton pattern, make one instance of your class at the start of your program and pass it around to its users. Singletons are really just as bad as global variables. Why? Because they are global variables.

I'm not sure how... pass it around is 'better' than global scope. Meaning not sure what problems you're avoiding here. If the scope is a single thread, no problem . If it's accessed from multiple threads, you have problems whether it's a global, singleton, or passed by reference. Not actually completely true, you can still have races in single threaded code. Consider two state variables that are effected by a shared…

> I'm not sure how... pass it around is 'better' than global scope.

- Readability: You can see what components use the thing by following the variable as it is passed around.

- Testability: Tests can pass in a mock thing.

- Maintainability: If you discover someday that you need two different instances of the thing to pass into two different subsystems, you can do that. (This happens a lot, and programmers are really bad at foreseeing it.)

- Security: Only the components to which you've passed the thing can possibly use it (subject to the memory safety guarantees of your language).

http://www.object-oriented-security.org/lets-argue/singleton...

Re: Singleton Pattern in Go

#64
post #34

Coding Pro Tip: Instead of using the Singleton pattern, make one instance of your class at the start of your program and pass it around to its users. Singletons are really just as bad as global variables. Why? Because they are global variables.

Depending on what you are trying to implement - passing an extra variable everywhere is just creating noise (because potentially you have to have an extra parameter to EVERY function or method). I believe in KISS - everything should be as simple as possible but not simpler. Believe it or not there are valid uses for a Singleton which, many would agree, include a simple logging class [1]. One could argue that you coul…

> because potentially you have to have an extra parameter to EVERY function or method

More often you have an extra parameter to class constructors, not every method. It's really not that bad, even when you choose to do it manually (as I do) rather than use a dependency injection framework.

> I believe in KISS - everything should be as simple as possible but not simpler.

I agree, which is why I avoid singletons because while they appear to reduce complexity in the short term they add horrendous amounts of complexity in the long term.

Re: Singleton Pattern in Go

#65
post #62

Earlier quoted context omitted.

No argument that Singletons make it difficult to unit test things but there are genuine cases where singletons are required: For instance, you don't want to end up creating multiple objects that read the configuration file, when one is enough. Or you certainly don't want to create too many objs that are heavy (like a cache that stores data heavy objects, or services, or god-objects (which are themselves an anti-patte…

Depends on what you mean by "singleton". If you define it loosely as "a type of which there is only one instance", fine, no problem -- of course those will exist. But if you define it as "globally-accessible mutable state", then the problems start. Usually, the "singleton pattern" is explicitly a technique for doing the latter. > For instance, you don't want to end up creating multiple objects that read the configura…

Nailed it. It's fine to use a singleton, but don't call it from within every class you use it in. Just pass a reference to the instance of the singleton. Call it once in the outermost scope.

Re: Singleton Pattern in Go

#66
Two things:

1) Unless you've explicitly checked that Go's memory model prevents read/write moves to allow double-checked locking, don't do it.

2) The pattern is usually a CAS after the check.

Re: Singleton Pattern in Go

#67
post #57

Earlier quoted context omitted.

There are exceptions to this rule--i.e. there are ways to not really be thread-safe but to have things work anyway--but they fall in the category of "you have to really, really know your CPU and be willing to write processor-specific code that just happens to work", so you can basically ignore them. My favorite is the libdispatch abuse of cpuid to flood the pipeline on Intel CPUs for this problem: https://www.mikeash…

An interesting exception is Lamport's Bakery: https://en.m.wikipedia.org/wiki/Lamport%27s_bakery_algorithm Thread safety without synchronisation primitives. I'm not sure it's ever actually a good idea to use it, though. EDIT: unless you count a fence as a synchronisation primitive.

[deleted]

Re: Singleton Pattern in Go

#68
post #18

Earlier quoted context omitted.

Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! If you must use a singleton, I'd really recommend doing the so-called "aggressive" approach, which should have really been named the "actually won't crash sometimes" approach.

+1 for the aggressive approach, mutexes are very fast in go. I got curious and wrote a quick little benchmark test: $ cat bench_test.go package main import ( "sync" "testing" ) func BenchmarkMutex(b *testing.B) { var m sync.Mutex for n := 0; n A set of mutex.Lock() & .Unlock() calls takes only 24.0ns on average to complete. Thus it's possible to lock/unlock more than 41 million times per second on the puny 2011 MacBo…

Try again with many goroutines trying to lock/unlock in parallel (and GOMAXPROCS>1), the results are quite different!

Re: Singleton Pattern in Go

#69
post #18

Earlier quoted context omitted.

Totally! I was going to post the same thing. Double-checked locking is either impossible or really hard to get right, depending on the language and architecture's guarantees! If you must use a singleton, I'd really recommend doing the so-called "aggressive" approach, which should have really been named the "actually won't crash sometimes" approach.

In modern Java, it's easy enough if you've been shown the pattern. What's hard is understanding/discovering it from first principles.

Someone apparently disliked this comment, but check out

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLo.... Scroll down to "Fixing Double-Checked Locking using Volatile." It's five lines of code without braces, and can be applied without any creativity or reasoning.

Re: Singleton Pattern in Go

#70
post #65
post #62

Earlier quoted context omitted.

Depends on what you mean by "singleton". If you define it loosely as "a type of which there is only one instance", fine, no problem -- of course those will exist. But if you define it as "globally-accessible mutable state", then the problems start. Usually, the "singleton pattern" is explicitly a technique for doing the latter. > For instance, you don't want to end up creating multiple objects that read the configura…

Nailed it. It's fine to use a singleton, but don't call it from within every class you use it in. Just pass a reference to the instance of the singleton. Call it once in the outermost scope.

Just wondering what value the singleton provided if you only obtain it once. Isn't the purpose so you can obtain it whenever you want? If you just use a regular object, you run the risk of accidentally making another instance somewhere else, but you always have that risk with any regular object anyway.
Post reply on HN