How to solve circular dependency without creating new package?

Issue

In golang want a plugins system with a global registry. Structure can be simplified as follows:

/plugins/registry.go
/plugins/plugin1/impl.go

registry.go:

package plugins

import "plugins/plugin1" // required for plugin1.MakePlugin

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry = []Factory{
  plugin1.MakePlugin,
}

impl.go:

package plugin1

import "plugins" // required for IPlugin

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}

How to solve without moving IPlugin to 3rd (e.g common) package?

PS. I thought if i return *Plugin from MakePlugin this will be compatible with Factory, but its not!!!

Solution

"How to solve without moving IPlugin to 3rd (e.g common) package?"

You have at least two options:

  1. move the registration to a 3rd (e.g. main) package.
  2. have each plugin register itself when imported by some other package.

Example #1

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package main

import (
    "plugins"
    "plugins/plugin1"
)

func init() {
    plugins.Register(plugin1. MakePlugin)
}

func main() {
    // ...
}


Example #2

package plugins

type IPlugin interface {
  Register() error
}

type Factory func(x int) IPlugin

var registry []Factory

func Register(ff ...Factory) {
    registry = append(registry, ff...)
}
package plugin1

import "plugins" // required for IPlugin

func init() {
    plugins.Register(MakePlugin)
}

type Plugin struct {
  x int
}

func MakePlugin(x int) plugins.IPlugin {
  return &Plugin{
    x: x,
  }
}
package main

import (
    "plugins"
    _ "plugins/plugin1" // will execute init() i.e. register
)

func main() {
    // ...
}

Answered By – mkopriva

Answer Checked By – Candace Johnson (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.