-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
Context
Package Initialization
When importing a package, it is initialized according to the sequence described in the Go specification. If that package has dependencies, it makes sense that these are initialized first, and that is what is described in the spec. In many instances, this is very useful and helps to write very succinct code, eliminating much boilerplate code.
Importing for Side Effects
In the Go specification, there is mention that it is possible to import packages for their side-effects:
An import declaration declares a dependency relation between the importing and imported package. It is illegal for a package to import itself, directly or indirectly, or to directly import a package without referring to any of its exported identifiers. To import a package solely for its side-effects (initialization), use the blank identifier as explicit package name:
import _ "lib/math"
Small Issue
Currently, the import order is predictable for packages with import relations. This is very useful and works flawlessly. However, as I've come to realize it, within a series of import statements in a single file, a package that is imported (for its side effects) early in the list of imports has no guarantee of early initialization. Consequently, the initializations are not ran in order, which makes results unpredictable at times.
Example Use Case - Mocking An Execution Environment Before Running Unit Tests
The package names here are not necessarily representative of what has caused this issue, they are just to explain the use case; let's say I have a package, packagea
, that initializes a connection to a server, either in its init()
or via variable initializers.
package somepackage_test
import _ "github.com/the-zucc/packageb" // this init() function sets an environment variable containing the server URL
import "github.com/the-zucc/packagea" // this package's init() function reads the environment variable
// Just imagine some unit tests here... :)
In this case, I've observed 2 things:
- There's no guarantee that
packageb
will be imported and initialized beforepackagea
-- in my case, the package imported the earliest was initialized at the end, effectively not propagating its side effects early enough in the program execution for them to apply to other package initializations, as the environment variable was not set which causedpackagea
to default to the "production code" server URL, and not the testing URL; - There isn't anything in the documentation or in the official Go specification referring to package initialization order within a series of import statements, or within a grouped import.
Proposed Solution
Enable some way of specifying that a package should be imported before any other package for its side effects. As an example, initialization behavior for grouped imports could remain the same, but for separate import statements, statement order could define the initialization order.
import _ "github.com/the-zucc/packageb" // this could be initialized first
import ( // and then the initialization behaviour could remain the same for this grouped import
"github.com/the-zucc/packagec"
"github.com/the-zucc/packagea"
)
EDIT: as mentioned in the comments, the proposed solution wouldn't work, unfortunately; however it still gives an idea of what a candidate implementation could look like.