Could adding variadic parameters to a function break existing code?

[亡魂溺海] 提交于 2020-02-23 09:36:41

问题


Is adding a variadic parameter to an existing Go function a breaking change?

For example:

// Old function
func Foo(a int)

// Updated to:
func Foo(a int, params ...string)

Callers of the API can omit the new parameter, so I would think the API is backwards-compatible.

Can anyone provide an example where a user of the old API could not use the new API without changing their code?


回答1:


I. Changing functions

Calling them will continue to work without modification, but since the function signatures do not match, that may easily break some code.

For example (try it on the Go Playground):

func Foo(a int)                    {}
func Foo2(a int, params ...string) {}

func main() {
    var f func(int)

    f = Foo
    f = Foo2 // Compile-time error!

    _ = f
}

The line f = Foo2 produces a compile-time error:

cannot use Foo2 (type func(int, ...string)) as type func(int) in assignment

So this is a backward incompatible change, don't do it.

The above example gave a compile-time error, which is the lucky / better case, but there may also be code that would only fail at runtime (non-deterministic if / when that happens), like in this example:

func Foo(a int)                    {}
func Foo2(a int, params ...string) {}

func main() {
    process(Foo)
    process(Foo2) // This will panic at runtime (type assertion will not hold)!
}

func process(f interface{}) {
    f.(func(int))(1)
}

Calling process(foo) succeeds, calling process(foo2) will panic at runtime. Try it on the Go Playground.

II. Changing methods

Your question was directed at functions, but the same "problem" exists with methods too (when used as method expressions or method values, for example see golang - pass method to function).

Additionally, this may break implicit interface implementations (it may make types not implement interfaces), like in this example (try it on the Go Playground):

type Fooer interface {
    Foo(int)
}

type fooImpl int

func (fooImpl) Foo(a int) {}

type fooImpl2 int

func (fooImpl2) Foo(a int, params ...string) {}

func main() {
    var f Fooer

    f = fooImpl(0)
    f = fooImpl2(0) // Compile time error!

    _ = f
}

Because signatures don't match, fooImpl2 does not implement Fooer, even though fooImpl does:

cannot use fooImpl2(0) (type fooImpl2) as type Fooer in assignment:
  fooImpl2 does not implement Fooer (wrong type for Foo method)
      have Foo(int, ...string)
      want Foo(int)


来源:https://stackoverflow.com/questions/55163005/could-adding-variadic-parameters-to-a-function-break-existing-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!