golang

Solving Golang Import Cycles (Import Cycle Not Allowed)

Import cycles, commonly known as import cycle not allowed errors, are a very common issue for new Golang developers.

Import cycles occur when two or more packages import each other, either directly or indirectly, which creates a circular dependency.

What Are Import Cycles?

In Go, the code is mainly organized into maintainable units called “packages”. Each package can depend on other packages, allowing the app to share the code and improve the readability.

Import cycles occur when the packages form a circular dependency chain. In other words, Package A imports Package B, and Package B imports Package A or another package that eventually imports Package A.

This circular relationship creates a problem because Go’s build system cannot determine the order in which the packages should be compiled which leads to an error.

Reasoning Behind Import Cycles

Before we dive into the technical weeds of why import cycles occur and how to debug them, let us first learn the reasoning behind the lack of support for import cycles in Go.

Go is a very simplistic but highly-efficient language that focuses heavily on faster compile time rather than the execution time.

Therefore, when you are compiling a Go code, the compiler pays heavily on the compile time rather than the most efficient machine code.

When it comes to import cycles, packages that import each other can dramatically increase the compile time as the code is compiled every time one of the dependencies is modified.

You can think of import cycles like an indirect infinite dependency recursion which is something that the Go compiler will not take kindly to.

They can also lead to memory leaks as each object is tied to the other and the reference will never reach zero. The cleanup for such objects become more than cumbersome.

Why Import Cycles Occur

The following are some of the reasons that you might encounter when you import the cycles in your codebase:

Poor Package Design – Probably, as a new Golang developer, you may create packages with overly complex dependencies which can lead to import cycles.

Refactoring Issues – Another reason why you might create the import cycles in Go is when refactoring the code. Trying to create a reusable code can lead to you create the import cycles.

Lack of Dependency Management – Not using a proper dependency management tool like Go modules can make it difficult to track and manage the package dependencies.

Shared Interfaces – If multiple packages depend on a common interface, it can lead to circular dependencies.

Example of Import Cycle

Let us create a simple example to demonstrate the import cycles in Go.

Suppose we have a package called “PackageX” and “PackageY”. In our code, “PackageX” depends on “PackageY” and “PackageY” depends on “PackageX”.

The following is an example code for “PackageX”:

package packageX
import (
    "fmt"
    "packageY"
)
func AFunction() {
    fmt.Println("Function in packageA")
    packageY.BFunction()
}

The following is an example code for “PackageY”:

package packageY
import (
    "fmt"
    "packageX"
)
func BFunction() {
    fmt.Println("Function in packageB")
    packageX.AFunction()
}

In this example, “packageX” imports “packageY” and “packageY” imports “packageX”, creating an import cycle.

Running the previous code should return an error as “import cycle not allowed”.

package packageX

imports packageY

imports packageX

Fix the Import Cycles in Go

To fix an import cycle, all you need is to restructure the code and remove the circular dependency while retaining the functionality.

Extract the Interfaces

If the packages are causing circular dependency due to shared interface, you can move the interfaces into a separate package. That way, each package can import the interface package without causing a cycle.

Dependency Inversion

Apply the Dependency Inversion Principle (DIP) by defining the abstract interfaces in the higher-level package and implementing them in the lower-level package. This reduces the direct dependencies between packages.

Conclusion

In this tutorial, we learned about the import cycles in Go. We also learned about import cycles, the example of import cycle, and the ways to fix them.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list