Search code examples
gostructnullconventions

Nil handling at method or constructor level?


Should I check for nil values in the constructor and then set an unexported struct field, or make the default struct value useful by checking for nil at method level?

type Foo struct{}

func (f *Foo) Baz() {}

var DefaultFoo = new(Foo)

type Bar struct {
    Foo *Foo
}

func (b *Bar) Baz() {
    if b.Foo == nil {
        DefaultFoo.Baz()
    } else {
        b.Foo.Baz()
    }
}

or

type Foo struct{}

func (f *Foo) Baz() {}

var DefaultFoo = new(Foo)

type Bar struct {
    foo *Foo
}

func NewBar(foo *Foo) *Bar {
    if foo == nil {
        foo = DefaultFoo
    }
    return &Bar{foo}
}

func (b *Bar) Baz() {
    b.foo.Baz()
}

Solution

  • I don't think there is a "right" answer for this.

    Having said this, the approach usually seen in the Go base libraries is letting the objects be created without any constructor, with nil or zero values in its fields, and then make the methods have logic to use or return useful defaults.

    Take a look at the http.Client implementation for example:

    https://github.com/golang/go/blob/master/src/net/http/client.go

    It will basically let you create a new client by just doing:

    client := &http.Client{}
    

    You can then populate the fields of the object if you want to override defaults, otherwise it'll check for nil in different methods to provide default behaviour, for example:

    https://github.com/golang/go/blob/master/src/net/http/client.go#L195

    func (c *Client) transport() RoundTripper {
        if c.Transport != nil {
            return c.Transport
        }
        return DefaultTransport
    }