wire
wire copied to clipboard
wire: support Close methods
It's common for constructor functions to return values that have a Close method that's used to clean up the value's associated resources. This doesn't fit easily with the convention used by wire of using a func()-typed return value. This means it's always necessary to add an adaptor function that returns a cleanup function that calls the Close method.
As a possible feature, it might be possible to add a wire function that makes this easier:
// Cleanup specifies that cleanupFunc should be used to
// clean up values of a given type. The cleanupFunc argument must be
// of type func(T) or func(T) error where T is the type to be cleaned up.
// If it returns an error, the error value will be discarded.
//
// For example:
// wire.Bind(
// openDatabaseFile,
// openDatabase,
// wire.Cleanup((*os.File).Close),
// )
func Cleanup(cleanupFunc interface{}) Cleaner
As mentioned in #184 , this could be achieved by an anonymous cleanup function.
#184 is about provider functions, not cleanup functions. We can already have anonymous cleanup functions:
func newFoo(a *A, b *B) (*somePkg.Foo, func(), error) {
foo, err := somePkg.NewFoo()
if err != nil {
return nil, nil, err
}
return foo, func() {
foo.Close()
}, nil
}
but you have to write this kind of wrapper function for every provider function that returns a Closer (which is idiomatic Go) rather than returning a cleanup function, which can be tedious.
So it doesn't seem to me that #184 is directly relevant, but perhaps I'm missing something. Could you explain how fixing #184 would help in this case, please?
Hi @rogpeppe -- can you just add a function to do the wrapper?
E.g.,
func CloseFn(c io.Closer) func() { return func() { c.Close() } }
and then
func newFoo(...) (..., func(), error) {
...
return foo, CloseFn(foo), nil
}
This seems simpler than adding a new wire function, and gives you access to the error returned by the io.Closer in case you want to log it or something.
(reopening while we discuss)
@vangent AFAICS that's exactly the approach that I alluded to in the issue description:
This means it's always necessary to add an adaptor function that returns a cleanup function that calls the Close method.
This is not very convenient as it means you'll have to essentially duplicate the signature of the function being provided and change it every time the function changes. It's that inconvenience that prompted me to create the issue - it's a pain point that makes it a little harder to sell wire as a convenient dependency-injection tool.
duplicate the signature of the function being provided and change it every time the function changes
Sorry, can you clarify what you mean by that? Is it that you have a constructor function that creates a *somePkg.Foo but doesn't return a func(), and so you have to create a new function with a similar signature just to call that constructor and return the additional func()? Do you not want to change the original constructor function to add the func() return?
IIUC, we originally considered supporting io.Closer as cleanup functions (instead of or in addition to func(), but it was not obvious what to do with the returned error. @zombiezen