Factory method in golang suffers from cyclic dependency - go

I realize questions about cyclic dependencies have been answered before, however, the answers usually simply say to merge packages. So long story short, I have an interface which many types will implement. I want to have a way of choosing which one of these types is to be used during runtime using its name. This would also be used for serialization. I read in the name of the class and then instantiate the correct one.
I have used the strategy pattern. There is a Base interface in package A.
package A
import (
"../C"
)
type Base interface {
doStuff(p C.Profile) int
}
type Operation struct {
Base Base
Data int
}
func (o *Operation) execute(p C.Profile) int {
return o.Base.doStuff(p)
}
Then, there are types that implement that interface in package B.
//file Impl1.go
package B
import (
"../C"
)
type Impl1 struct {}
func (b *Impl1 ) doStuff(p C.Profile) int {
...
}
//file Impl2.go
package B
import (
"../C"
)
type Impl2 struct {}
func (b *Impl2 ) doStuff(p C.Profile) int {
...
}
Then in package C i have struct Foo with a field of type Base. This field can point to any of the implementations from package B. We can choose the implementation during runtime. This is the struct that I eventually want to serialize.
package C
import (
"../A"
"../B"
)
type Foo struct {
bar A.Base
baz []Profile
...
}
func (f *Foo) changeBar(name string, data int) {
switch name {
case "Impl1":
f.bar = Operation{Base: B.Impl1{}, Data: data}
case "Impl2":
f.bar = Operation{Base: B.Impl2{}, Data: data}
...
}
EDIT: Also in the C package, we have the Profile, which is the reason A and B packages need to import it.
This code has a cyclic dependency C -> B -> C. An obvious solution would be to move Profile to a different package. But this is not possible because Profile (and many other similar types in the C package) and Foo are very tightly coupled and belong in the same package (maybe not so apparent in this minimal working sample). This is what other answers to these type of questions suggest, but I want to learn how to make it work, using good practices i learned from using other languages.
Another solution would be to somehow move the factory method changeBar to another package and only use it on the outside of the C package (thus avoiding the cycle), passing it results to C as parameters, but there are cases (serialization in particular) where I actually need it on the inside of the C package.
I have put a lot of time into figuring out this issue but all I end up with is either have everything in one huge package or have every single file in a separate package and have everything be exported. In other programming languages, there is the possibility to either have these cyclic dependencies or import one "class" at a time from a package. What is the way to go in go?

You can break the dependency from C to B using a type registry:
package C
import "A"
var TypeRegistry = map[string]func() A.Base {}
func (f *Foo) changeBar(name string, data int) {
if factory, ok:=TypeRegistry[name]; ok {
f.bar=Operation{Base:factory(),Data:data}
}
}
Then register your implementations in any package:
package B
import "../C"
func init() {
C.TypeRegistry["myType"]=func() A.Base { return MyType{}}
}

Related

Go package selector based on condition

We have 2 packages that implement the same function signatures. In my main I need to switch out the package being used based on a condition:
import (
packageA "deployment/sdk/packageA"
packageB "deployment/sdk/packageB"
)
someCondition := true
var packageToUse ?
if someCondition {
packageToUse = packageA
} else {
packageToUse = packageB
}
packageToUse.DoSomething()
Of course, this doesn't compile. I don't know what type to use for packageToUse. This approach is probably an anti-pattern. I'm just not sure the approach I should be taking.
any suggestions?
The error I get is use of package without selector
It is very much a pattern - aside from the dynamic import. It is called „Interfaces“.
Given an interface definition like
type Stringer interface{
String() string
}
and the type Foo implementing said interface
type foo int
func(f foo)String() string{
return fmt.Sprintf(”%d”,f)
}
as well as Bar implementing said interface
type bar string
func (b bar) String()string {
return string(b)
}
one can actually use both as a parameter for a function baz
func baz(s Stringer){
fmt.Println(s.String())
}
Note that unlike other languages, you do not have to declare the interfaces a type implements - as long as a type happens to factually implement an interface, the go compiler is ok with it. Run on Playground
So, with regards to your question of package imports: Unless you have ginormous dependency trees to import, it really is not worth the hassle.
Say we talk of an application using either BBolt or etcd and for good measure some MongoDB. The resulting size to include all of them, while relatively speaking is quite astonishing, is negligible. I compiled a go program with imports of bbolt, bbolt & etcd and bbolt, etcd & mongodb. These are the results in bytes.
11734884 size_all
2455544 size_bolt
10307700 size_boltetcd
We are talking of a few megabytes in file size. So say you use either Bolt or etcd or MongoDB, do you really want to jump through all the hoops and loops required to get dynamic imports done properly? I for my part would neither want to do it nor would I want Go to provide such a feature.
"Premature optimization is the root of all evil (or at least most of it) in programming."
– Donald Knuth
This isn't quite what you asked, but this is how I would accomplish the goal if I were you:
// I assumed both package functions have the same signature, so you can use a type
// TODO: Actual function signature you want to use here
type myFn func() error
var fnToUse myFn
if someCondition {
fnToUse = packageA.Func1
} else {
fnToUse = packageB.Func2
}
fnToUse()
Following up a bit on comment about using an interface
I would step back a bit and see if this can be better solved using an
interface that you provide the concrete class for in the condition
statement.
package packageA
type Thing struct {
}
func (t Thing) DoSomething() {
}
--
package packageB
type Thing struct {
}
func (t Thing) DoSomething() {
}
--
package main
import (
"packageA"
"packageB"
)
type PackageUser interface {
DoSomething()
}
func main() {
var pu PackageUser
if (condition) {
pu := packageA.Thing{}
} else {
pu := packageB.Thing{}
}
pu.DoSomething()
}

Create equivalent interface of another package with an interface as argument

I am practicing writing idiomatic Go code and discovered that interfaces should be declared in packages which are consuming them since they're implicit. However I came to this situation where by in the second package (package b) I want a function to call the receiver function of a struct in package a without coupling it tightly.
So naturally, I declare an interface in package b with the signature of the function I want to call from package a. The problem is that this function accepts an argument of a certain type which is an interface declared in package a. As I don't want package b to import package a, I defined an interface in package b with the exact same signature as the one which exists in package a. The playground link below shows the example code.
Playground
package main
import (
"fmt"
"log"
)
func main() {
manager := &Manager{}
coach := NewRunnerCoach(manager)
fmt.Println("Done")
}
// package a
type Runner interface {
Run()
}
type Manager struct {
}
func (o *Manager) RegisterRunner(runner Runner) {
log.Print("RegisterRunner")
}
func (o *Manager) Start() {
log.Print("Start")
}
// package b
type RunnerCoach struct {
runner *FastRunner
}
func NewRunnerCoach(registerer runnerRegisterer) *RunnerCoach {
runnerCoach := &RunnerCoach{&FastRunner{}}
registerer.RegisterRunner(runnerCoach.runner)
return runnerCoach
}
type FastRunner struct {
}
func (r *FastRunner) Run() {
log.Print("FastRunner Run")
}
// define ther registerer interface coach is accepting
type runnerRegisterer interface {
RegisterRunner(runner RunnerB)
}
// declaring a new interface with the same signature because we dont want to import package a
// and import Runner interface
type RunnerB interface {
Run()
}
This code does not compile. So the question here is that, am I using interface wrongly or should concrete types be defined in a separate package or lastly, is there a better code pattern for the problem I'm trying to solve?
EDIT: To clarify, package a and b does not import each other. The main() code exists in a separate package which connects these two.
IIUC, your question is not about packages but boils down to whether a function (or method)
can be typecast to another function which takes arguments with equivalent, but
not the same interface types.
Something like this: (Go Playground)
package main
type I1 interface{}
func f1(x I1) {}
func main() {
f := (func(interface{}))(f1)
f(nil)
}
Compilation error: ./g.go:8:26: cannot convert f1 (type func(I1)) to type func(interface {})
The answer appears to be no, because Go doesn't consider func (I1) to be
equivalent to func (interface{}). The Go spec says this
A function type denotes the set of all functions with the same parameter and result types.
The types func (I1) and func (interface{}) do not take the same parameters, even though
I1 is defined as interface{}. Your code fails to compile for a similar
reason because func (runner RunnerB) is not the same as func (runner Runner) and hence the method set of *Manager is not a superset of the
interface runnerRegisterer.
Coming to your original question:
I am practicing writing idiomatic Go code and discovered that interfaces
should be declared in packages which are consuming them since they're
implicit.
Yes, the idea is good but it doesn't apply to your implementation the way you
think it does. Since you're expecting to have different implementations of
runnerRegisterer and they must all have a method with the same signature
using the Runner interface, it makes sense to define Runner in a common
place. Also, as seen above Go wouldn't allow you to use a different interface
in the method signatures anyway.
Based on my understanding of what you're trying to achieve, here's how I think
you should re-arrange your code:
Define RunnerRegisterer (note: this is public) and Runner in one
package.
Implement your RunnerCoach in the same package and use the above
interfaces. Your RunnerCoach consumes types that implement the interfaces,
so it defines them.
Implement your runners in another package. You don't define the Runner
interface here.
Implement your Manager in another package, which uses the interface
Runner defined in RunnerCoach's package because it must take that type
as an argument if it wants to be used as a RunnerRegisterer.
The Solution
You've got a type that is used in two packages, A and B. Package A imports package B.
You have to avoid circular dependencies, so you have three choices:
Define the type in package B, so it will be available in both
packages.
Define the type in package C and have both A and B import package C.
Change your design such that the type is not used in both A and B.
These are your choices whether that type is an interface or any other type.
Choose the option that best fits your design goals.
The Rule / Idiom
I am practicing writing idiomatic Go code and discovered that
interfaces should be declared in packages which are consuming them
since they're implicit.
I get the impulse/idea - the problem is it's not very practical. Interfaces would be less useful if they could only be consumed in the package in which they are defined. The standard library is full of code that violates this axiom. Therefore I do not think the rule as presented -- applying to all interfaces in all situations, designs and contexts -- is idiomatic.
For example, look at the bytes package. func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) consumes io.Reader, an interface defined in another package. func (r *Reader) WriteTo(w io.Writer) (n int64, err error) consumes io.Writer, an interface defined in another package.

Multiple sets of const names with scope in Go

I have a Go application that requires an unbounded number of sets of constants. The application also requires that I be able to map strings to (integer) consts, and vice versa at runtime. The names of the constants are guaranteed only to be valid identifiers, so it's a near certainty that there will be duplicate const names. In particular, each set of constants has an element called "Invalid". In C++11, I'd use enum classes to achieve scope. In Python, I'd probably use class variables. I'm struggling to find an idiomatic way to express this in Go. Options that I've looked at include:
Using a separate package for every set of consts. This has lots of disadvantages, because I'd rather the whole set be in the same package so that I can build support for these sets at the package level, and so that I can test the whole lot without overly complicating the test code to do multi-package testing at once.
first.go:
package first
type First int
const (
ConstOne First = iota
ConstTwo
Invalid = -1
)
func IntToCode(fi First)string { ... }
func CodeToInt(code string)First { ... }
second.go:
package second
type Second int
const (
ConstOne Second = iota
ConstTwo
Invalid = -1
)
func IntToCode(se Second)string { ... }
func CodeToInt(code string)Second { ... }
example.go:
import (
"first"
"second"
)
First fi = first.CodeToInt("ConstOne")
Second se = second.Invalid
Using the tried-and-true technique of a globally unique prefix for each const. Given, though, that the number of sets is really big, having to essentially invent and manage a bunch of namespaces using a coding convention is awkward at best. This option also forces me to modify the names of the consts (which is the whole point of using them).
first.go:
package mypackage
type First int
const (
FI_CONSTONE First = iota
FI_CONSTTWO
FI_INVALID = -1
)
func IntToCode(fi First)string { ... }
func CodeToInt(code string)First { ... }
second.go:
package mypackage
type Second int
const (
SE_CONSTONE Second = iota
SE_CONSTTWO
SE_INVALID = -1
)
func IntToCode(se Second)string { ... }
func CodeToInt(code string)Second { ... }
example.go:
package mypackage
import (
"first"
"second"
)
First fi = first.CodeToInt("ConstOne")
Second se = SE_INVALID
What's a better, more idiomatic solution? I'd love to be able to say things like:
First fi = First.Invalid
but I haven't been successful in coming up with an approach that allows this.
You could have separate packages for your separate code sets and a single package for defining the higher level functionality associated with codes and write tests for that higher level package.
I haven't compiled or tested any of this:
E.g. for a code set:
package product // or whatever namespace is associated with the codeset
type Const int
const (
ONE Const = iota
TWO
...
INVALID = -1
)
func (c Const) Code() string {
return intToCode(int(c)) // internal implementation
}
type Code string
const (
STR_ONE Code = "ONE"
...
)
func (c Code) Const() int {
return codeToInt(string(c)) // internal implementation
}
E.g. for the higher level functions package:
// codes.go
package codes
type Coder interface{
Code() string
}
type Conster interface{
Const() int
}
func DoSomething(c Coder) string {
return "The code is: " + c.Code()
}
// codes_product_test.go
package codes
import "product"
func TestProductCodes(t *testing.T) {
got := DoSomething(product.ONE) // you can pass a product.Const as a Coder
want := "The code is: ONE"
if got != want {
t.Error("got:", got, "want:", want)
}
}
Edit:
To retrieve the const for a particular code you could do something like
product.Code("STRCODE").Const()
Maybe it's better if Const() returns a Coder so that product.Code("ONE").Const() can be a product.Const. I think if you play around with it there are a few options and there will be a good one in there somewhere.

Circular import with structs [duplicate]

This question already has answers here:
Registering packages in Go without cyclic dependency
(2 answers)
Closed 7 years ago.
I have a project with several modules in Go. I am having problem with circular imports because of the scenario below:
Details
A module Game contains a struct with the current Game state. Another module (Modifier) is doing some game specific stuff and calculations and therefore modifies the game state. Because of this, Modifier will need the struct Game, but not any methods from Game. Modifier is called from Game and here we have the circular import.
Problem:
Game initiates Modifier
Modifier needs Game struct
It seems to me that this is a common scenario, so I wonder how I should solve it in the best way. My solution would be to create a third module "Structs" which just contains all the structs for the whole application. Is this a good solution?
With the 3rd package option:
yourgame/
state/
state.go
modifier/
modifier.go
main.go
main.go would glue the two components together:
import "yourgame/state"
import "yourgame/modifier"
type Game struct {
state state.State
modifier modifier.Modifier
}
func main() {
// something like:
var game Game
game.modifier.Modify(game.state)
}
This approach is probably too tightly coupled though. Rather than manipulating an essentially global state object, I would try to slice up the data into just what you need for the modifier.
Reasoning in the abstract is hard, so here's a concrete example of what I mean. In your game:
type Object struct {
ID, X, Y int
// more data here
}
type Game struct {
Objects map[int]*Object
}
In your "modifier", let's suppose we had an AI module that moves an object. If all he cares about is the position of a single object you can create an interface:
// in yourgame/modifier
type Object interface {
GetCoordinates() (int, int)
SetCoordinates(int, int)
}
type Modifier struct {}
func (m *Modifier) Update(obj Object) { }
Then we just have to add those methods to our original Object:
type (obj *Object) GetCoordinates() (int, int) {
return obj.X, obj.Y
}
type (obj *Object) SetCoordinates(x, y int) {
obj.X, obj.Y = x, y
}
And now you can pass objects to your modifier without needing a cyclic dependency.
Now if it turns out your "modifier" interface ends up looking almost exactly the same as your game object, then a 3rd package of structs is probably reasonable so you aren't always repeating yourself. For an example consider net/url.
Normally if package B has code that directly reads/modifies A.Type then that code should be in package A.
At least the parts of it if that need direct access should.
To split something between separate packages A and B you'd normal try to isolate an API for access to A.Type that can be expressed as an interface. Then B would define and use this interface and A.Type would implement it (implicitly, without needing to include B's definition of it).
Then something (possibly A, possibily a separate package) would use B by passing an A.Type or *A.Type value as appropriate.
Or depending on your design the relationship could be reversed, with B.OtherType implicitly implementing an interface defined and used by A.
Or both A and B could use each other only through interfaces; it all depends on the details.
E.g. perhaps something like:
package Game // "A"
type State struct {
data int // etc
}
func (s State) IsValid() bool { return true }
func (s *State) ChangeY(arg int) error { return nil }
// …etc…
and:
package Modifier // "B"
type GameState interface {
IsValid() bool
ChangeY(int) error
}
type M struct {
s GameState
//…
}
func New(s GameState) *M {
return &M{s: s}
}
func (m M) DoSomething() {
if s.IsValid() {
// …
}
s.ChangeY(42)
// …etc…
}
I'd define type(Game in this case) and all its methods in same one package. You can't even define methods on type imported from another package according to language spec,
//you should first do
type MyPackageType ImportedType
//and only then
func (foo MyPackageType) Modify() {
...
}

Assignment of one struct to other struct of "structural identical" type

My problem is like this: I have a MyMail package which provides a function SendMail(MyMail.Mail) to other packages. MyMail uses the package LowLevelMail and its function Send(LowLevelMail.Mail) to actually send Mails. MyMail.Mail and LowLevelMail.Mail are identical in the sense that they define the "same struct" (i.e. equally named and typed fields).
SendMail(m MyMail.Mail) has to convert m to LowLevelMail.Mail before using Send(LowLevelMail.Mail. newmail := LowLevelMail.Mail(m) won't work. But this could be possible as the compiler should be able to see that the fields of the two structs are identical. Maybe it's not a good idea to support this because of not exported fields.
1) Can I somehow assign m to newmail without doing it all by hand (and without losing all type safety?)? The by hand method would cause some pain (the struct does not solely consist of simple types which can be assigned to the other struct's).
2) Is there a better solution to the whole problem (i.e. "I don't want to use other packages' types in my API because I don't want my packages' clients to depend on a foreign API. This foreign API may change or I might decide at some point to not use it any more.").
Update: I missed an important point: LowLevelMail.Mail has a field of type LowLevelMail.Address which also is "redefined" in MyMail as MyMail.Address.
This works :
type T1 struct {
a int
b string
}
type T2 struct {
a int
b string
}
func main() {
t1 := T1{2, "test"}
t2 := T2(t1)
fmt.Println(t2)
}
Isn't it what you're looking for ?
If your question is about how to do this when T1 and T2 are in different packages and don't export their fields, well, allowing this would simply nullify the privacy of those fields so of course that's not possible.
Your problem seems to be something like this:
package lowlevelmail
type Mail struct { P int; p int}
func Send(m Mail) { }
and
package mymail
import "lowlevelmail"
type Mail lowlevelmail.Mail
func Send(m Mail) { lowlevelmail.Send(lowlevelmail.Mail(m)) }
and
package main
import "mymail"
func main() {var m mymail.Mail; mymail.Send(m)}

Resources