Regarding "Accept interfaces, return concrete types", how can it be applied for structs that represent a payload/value?
For example in package first, logger is defined as:
type logger interface {
Debugf(template string, args ...interface{})
Errorf(template string, args ...interface{})
Infof(template string, args ...interface{})
}
And package first only accepts a logger that implements the logger interface.
Now lets assume there is a need for passing a struct too, like some config or state.
This causes importing the original package that, that config or state struct resides in; while package first is happily accepting other things from that package using interfaces.
For example in package second there is some tool that is represented using this interface in package first:
type cloner interface {
Clone() (*second.State, error)
}
As it can be seen, now package first has to explicitly import package second, because of the type *second.State.
Currently I break things by renaming the second package to something meaningless when importing like:
type cloner interface {
Clone() (*p2nd.State, error)
}
But this is not really a work around and package second leaks into the scope of package first anyway.
Is there a way to actually achieve this?