Singleton in go
Asked Answered
E

10

67

How does one implement the Singleton design pattern in the go programming language?

Emalee answered 1/12, 2009 at 0:12 Comment(3)
how do you implement a Singleton in any language? :DColliery
Hopefully it's impossible.Soapwort
why the gruff with singletons? Am I missing a new trend? The singleton design pattern has its uses.Billingsgate
H
72

Setting aside the argument of whether or not implementing the singleton pattern is a good idea, here's a possible implementation:

package singleton

type single struct {
        O interface{};
}

var instantiated *single = nil

func New() *single {
        if instantiated == nil {
                instantiated = new(single);
        }
        return instantiated;
}

single and instantiated are private, but New() is public. Thus, you can't directly instantiate single without going through New(), and it tracks the number of instantiations with the private boolean instantiated. Adjust the definition of single to taste.

However, as several others have noted, this is not thread-safe, unless you're only initializing your singleton in init(). A better approach would be to leverage sync.Once to do the hard work for you:

package singleton

import "sync"

type single struct {
        O interface{};
}

var instantiated *single
var once sync.Once

func New() *single {
        once.Do(func() {
                instantiated = &single{}
        })
        return instantiated
}

See also, hasan j's suggestion of just thinking of a package as a singleton. And finally, do consider what others are suggesting: that singletons are often an indicator of a problematic implementation.

Haematogenesis answered 2/12, 2009 at 21:50 Comment(8)
Having not tested this code, it looks to me like you'd only be able to get an instance of single the first time you call New(). After that, you just get nil. If you lose track of your one instance and it gets garbage collected, you can't create any more. Wouldn't you want to keep track of the pointer to the instance of single and return that instead of nil?Jazzy
Agreed; I've changed the code to do so, although linguistically I'm not very happy with New() returning something other than a fresh object. In another language, I probably would have raised an exception when trying to instantiate the object a second time. Note that, with this approach, the singleton will never actually go out of scope.Haematogenesis
Also, I'll point out again that a better way to think about this is probably hasen j's Pythonic approach: treat a package as your singleton, which the language enforces for you already.Haematogenesis
Perhaps overlooked; would a singleton in Go also need to deal with synchronization? What if several goroutines call New() at the same time and then all evaluate if instantiated = nil to true ?Azure
you don't need to init single to nil since that's the default value, right?Billingsgate
This example is not thread-safe, see : marcio.io/2015/07/singleton-pattern-in-goSkellum
I've updated the example to use sync.Once, which is seems to be the most idiomatic way to accomplish this right now.Haematogenesis
Go's happens before says that "func passed to sync.Do only gets called once". My question is can other go routines see fully constructed instantiated object immediately after sync.Do returns? If you take java for example instantiated needs to be volatile for other threads to see fully constructed instantiated value.Mydriatic
H
23

The best approach will be:

 package singleton

 import "sync"

 type singleton struct {
 }

 var instance *singleton
 var once sync.Once

 func GetInstance() *singleton {
     once.Do(func() {
         instance = &singleton{}
     })
     return instance
 }

You should read this Link

Hynes answered 29/10, 2015 at 9:55 Comment(0)
H
10

Just put your variables and functions at the package level.

Also see similar question: How to make a singleton in Python

Hardenberg answered 1/12, 2009 at 0:34 Comment(0)
T
9

I think that in a concurrent world we need to be a bit more aware that these lines are not executed atomically:

if instantiated == nil {
    instantiated = new(single);
}

I would follow the suggestion of @marketer and use the package "sync"

import "sync"

type MySingleton struct {

}

var _init_ctx sync.Once 
var _instance *MySingleton

func New() * MySingleton {
     _init_ctx.Do( func () { _instance = new(MySingleton) }  )
     return _instance 
}
Tenerife answered 19/11, 2012 at 18:0 Comment(4)
any reason you're prepending the unexported variables with _?Billingsgate
Hi @fabrizioM , I have a question here: your code is thread-safe. But there is another problem: the struct name is MySingleton - so we can init an object without calling New(): secondInstance := MySingleton{}.Pressing
However, if the struct name is changed to mySingleton, we have another problem: in different package we can only get the instance, but cannot pass around: obj := singletonpkg.New() is OK - but some function like func process(singletonpkg.mySingleton obj) { ... } is NOT OK. So, how can we implement the "correct" Singleton in go ?Pressing
@Pressing if mySingleton implements an exported interface, say SingletonInterface, you can have the New function return an instance of the interface, not the unexported type.Laspisa
W
4

Before trying to find a way to bend Go to your will, you might want to take a look at some articles:

In summary, over time people have found singletons to be less than optimal, and imho especially if you are trying to do any test-driven development: on many levels they are pretty much as bad as global variables.

[disclaimer: I know its not a strict answer to your question but it really is relevant]

Windsail answered 1/12, 2009 at 0:31 Comment(3)
Isn't the Unix philosophy (small, sharp tools) similar to using Singleton classes?Janssen
Sorry, but this should not be up-voted. Does not answer the question. None of the sources have anything to do with the Go programming language either. This is not the place for religious debates on coding patterns.Superannuate
How to model the boolean value for true if not by a singleton?Grosbeak
B
4

Easy peasy as you can see in the following code:

package main

import (
    "fmt"
    "sync"
)

type singleton struct {
    count int
    sync.RWMutex
}

var instance singleton 

func GetInstance() *singleton {
    return &instance 
}

func (s *singleton) AddOne() {
    s.Lock()
    defer s.Unlock()
    s.count++
}

func (s *singleton) GetCount() int {
    s.RLock()
    defer s.RUnlock()
    return s.count
}

func main() {
    obj1 := GetInstance()
    obj1.AddOne()
    fmt.Println(obj1.GetCount())
    obj2 := GetInstance()
    obj2.AddOne()
    fmt.Println(obj2.GetCount())    
    obj3 := GetInstance()
    obj3.AddOne()
    fmt.Println(obj3.GetCount())
}

Expected result would be:

1 2 3

Because you're accessing to the same resource. That's the reason I've added mutex in order to be concurrent proven accessing count attribute from multiple processes. :-)

Source:

https://play.golang.org/p/2XnLztX8Gs5

Boar answered 1/8, 2019 at 9:18 Comment(0)
E
3

You can do initialization using the once package:

This will ensure that your init methods only get called once.

Ervinervine answered 1/12, 2009 at 1:35 Comment(1)
There is no once package. I guess it was removed?Shoreward
C
1

Just have a single static, final, constant, global, application-wide instance of the Object you want.

This however contradicts the OO paradigm. Its use should be limited to primitives and immutable objects, not to mutable objects.

Chopstick answered 1/12, 2009 at 0:42 Comment(0)
B
1

You should be aware that Once.Do is serious about executing the code only once. That means, the code is always executed only once, even though it might have panicked:

from https://golang.org/pkg/sync/#Once.Do

If f (note: the once logic) panics, Do considers it to have returned; future calls of Do return without calling f.

I used mutexes instead to ensure unique initialisation of a global configuration variable to overcome this restriction:

Bankston answered 7/1, 2016 at 19:0 Comment(0)
M
0

I think if you want something like a singleton in Go you should try and think about what you're trying to achieve. Unlike Java or C#, Go has no concept of "static" classes, so the traditional distinction is less clear. In my mind, the key point you'd want from a singleton is not allowing others to construct it. To that end, I think it can achieved more simply: export an interface, implement an unexported class which implements this interface, and export a single instance of it. For instance:

var DefaultTransformer Transformer = &transformer{}

type Transformer interface {
    Transform(s string) string
}

type transformer struct {
    
}

func (t *transformer) Transform(s string) string {
    return s + "1"
}

var _ Transformer = (*transformer)(nil)

As the other answers show, there are many more literal ways you can implement the singleton pattern in Go, but they strike me as answers that start from the premise that the pattern must be copied exactly, rather than starting from solving a real problem you have in Go.

Magnetism answered 15/5, 2021 at 17:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.