Search code examples
govariadic-functionssemantic-versioning

How to do versioning in Go when adding a variadic parameter to a constructor?


I believe adding variadic function to a regular function or method is breaking change based on this post. But what about adding variadic parameters to a constructor function? like adding Functional Options.

By using semver this code is v1.0.0

type Foo struct{}

// constructor with default behavior
func NewFoo() *Foo {
    return &Foo{}
}

Adding a variadic parameter

type Foo struct{}

type Option func(&Foo)

// constructor with option
func NewFoo(opts ...Option) *Foo {
    // process option before return
    // ...
    return &Foo{}
}

Old code still fine when calling the constructor function and no one assigns constructor to a variable and passing around constructor to another function like in this case.

So, in the above code, should I increment the major version to v2.0.0 or the minor one to v1.1.0?


Solution

  • In Go, should I increment the major version to v2.0.0 or the minor one to v1.1.0?


    In Go, the NewFoo function types

    v1.0.0:

    type Foo struct{}
    
    func NewFoo() *Foo {}
    

    and

    v2.0.0:

    type Foo struct{}
    
    type Option func(*Foo)
    
    func NewFoo(opts ...Option) *Foo { }
    

    are distinct types. That makes it a breaking change, an update to the major version number.


    However, it's not really a major change, just an extension, so update the minor version number. Use similar but distinct function names. For example, NewFoo and NewFooOpts.

    v1.1.0:

    type Foo struct{}
    
    func NewFoo() *Foo {
        return NewFooOpts()
    }
    
    type Option func(*Foo)
    
    func NewFooOpts(opts ...Option) *Foo {
        var foo Foo
        for _, opt := range opts {
            // handle opt
            _ = opt
        }
        return &foo
    }
    

    Playground: https://play.golang.org/p/HcN1WCi0YK4

    Use the comments documenting the functions to provide guidance to the user as to which function to use. For example, perhaps function NewFoo is deprecated in favor of function NewFooOpts.


    No one assigns constructor to a variable and passing around constructor to another function.


    Since some one does, the statement is false.