Home > Software design >  In golang, import cycle not allowed, is the principle really a good solution?
In golang, import cycle not allowed, is the principle really a good solution?

Time:11-01

I had ask it in github issue yesterday, and one of the contributors say that I should ask it at this site, so I just paste my question at stackoverflow.

What version of Go are you using (go version)?

$ go version
go version go1.17.1 windows/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env

What did you do?

I write simple code to try to describe real world, but "Import cycle not allowed" will compile error. So I could only rewrite the simple code to complex code.

"Import cycle not allowed" is a right principle, but it is not a principle to makes code simple, it makes code more complex.

Is it a temporary principle or a permanent principle?

Is it designed after many consider and discuss, or only for personal preference?

I ask this question, because I think in real world, everything interacts with each other naturally.

For example, a teacher enter a classroom, many students enter a classroom, then teacher choose student a to ask, then the student b ask teacher. It is a normal simple requirement.

But in golang, the below code could not compile success, because import cycle not allowed. It is so strange.

testgo
│  main.go
│
├─classroom
│      ClassRoom.go
│
├─student
│      Student.go
│
└─teacher
        Teacher.go
// main.go
package main

import (
    "testgo/classroom"
    "testgo/student"
    "testgo/teacher"
)

func main() {
    c := &classroom.ClassRoom{}
    t := &teacher.Teacher{}
    a := &student.Student{}
    b := &student.Student{}
    t.Enter(c)
    a.Enter(c)
    b.Enter(c)
    t.Ask(a)
    b.Ask(t)
    print(c)
}
// classroom/ClassRoom.go
package classroom

import (
    "testgo/student"
    "testgo/teacher"
)

type ClassRoom struct {
    Teacher  *teacher.Teacher
    Students []*student.Student
}

func (c *ClassRoom) AddTeacher(t *teacher.Teacher) {
    c.Teacher = t
}

func (c *ClassRoom) AddStudent(s *student.Student) {
    c.Students = append(c.Students, s)
}
// teacher/Teacher.go
package teacher

import (
    "testgo/classroom"
    "testgo/student"
)

type Teacher struct {
    TeacherName string
    InClassRoom *classroom.ClassRoom
}

func (t *Teacher) Enter(c *classroom.ClassRoom) {
    c.AddTeacher(t)
    t.InClassRoom = c
}

func (t *Teacher) Ask(s *student.Student) {

}
// student/Student.go
package student

import (
    "testgo/classroom"
    "testgo/teacher"
)

type Student struct {
    StudentName string
    InClassRoom *classroom.ClassRoom
}

func (s *Student) Enter(c *classroom.ClassRoom) {
    c.AddStudent(s)
    s.InClassRoom = c
}

func (s *Student) Ask(t *teacher.Teacher) {

}

Finally, it will compile error like below

package testgo
    imports testgo/classroom
    imports testgo/student
    imports testgo/classroom: import cycle not allowed

There are more examples.

In real world, Cat catch Rat, Rat escape from Cat. package Cat import package Rat, and package Rat import package Cat.

In real world, Animal eat Fruit, Fruit be eat by Animal. package Animal import package Fruit, and package Fruit import package Animal.

In real world, import cycle occur everywhere.

But in golang, import cycle not allowed.

What did you expect to see?

enable import cycle, just like the real world

What did you see instead?

import cycle not allowed

CodePudding user response:

It is a permanent principle. Circular dependencies increase compile time and GO is highly focused on fast compile time.

A solution to circular dependency is introducing a new interface in a new package. This interface should have all the methods that a circular dependent struct have and accessed by other circular dependent struct.

I found a clear notes about it https://medium.com/@ishagirdhar/import-cycles-in-golang-b467f9f0c5a0

CodePudding user response:

It is correct and well thought principal. If you understand and imbibe your use-case, you can avoid cycles. For eg:- student class should only have student related details, names, age, address etc etc. class should have things like capacity, address etc. There should be a separate class named schedule.go which would hold the mapping of class, student and teacher.

  • Related