How to add more functionality while using existing interfaces in golang? - go

Suppose I have an interface Foo, and I am adding a struct which needs methods of Foo and few additional methods also. In that case out of following two, which is considered to be best practice? Or if there is some other more appropriate third way, then do suggest.
Approach 1
type Foo interface {
methodA()
}
type Bar struct {
}
func (b Bar) methodA () {
...
}
func (b Bar) methodB () {
...
}
Approach 2
type Foo interface {
methodA()
}
type Bar struct {
Foo // this can be initialized with any concrete implementation of Foo
}
func (b Bar) methodB () {
...
}
Also, it will be great if it can be pointed out in which scenarios above approaches are better fit for? Thanks!

Technical note: first method assures you (besides mistakes in initializing the struct) you can call methodA on Bar, second one don't because you have to initialize the interface field with something respecting that interface to not have a nil deference error.
Note that using the second method methodA is not called on Bar but on the Foo embedded object!
Second method is useful if you have a common implementation that can be shared by many objects and is self containing, i.e. consider you wanna know if an object implements a Log method to be sure you can log something with that object: in this case you can have a method that returns a Logger and set the interface field with that. Example follows:
package main
import "fmt"
type Logger interface {
Log(string)
}
type ConsoleLogger struct {} // See? No external dependencies
func (Cl ConsoleLogger) Log(msg string) {
fmt.Println(msg)
}
type A1 struct {
Logger
}
type A2 struct {
Logger
}
func main() {
a := A1{ConsoleLogger{}}
b := A2{ConsoleLogger{}}
a.Log("Test")
b.Log("Test")
}
Embedding objects is useful for dispatching method calls, remember it's just sintactic sugar in the end so besides passing the containing object you don't have any way to use its fields.
If Logger interface had to use outer object (A1 and A2) data in some sort of way than this method would be awkward because you would have to initialize the interface object which would then store some reference to the needed data with a waste of memory in some cases.
IMHO method one forces you to write more code but you are more free in the interface implementation and you can mix the two approaches by embedding a Logger and then override the Log method in A1 struct.
Additionally, you can nonetheless pass something to build something implementing an interface:
package main
import "fmt"
type Logger interface {
Log(string)
}
type ConsoleLogger struct {
Prepend string // string to prepend to log message
}
func (Cl ConsoleLogger) Log(msg string) {
fmt.Println(Cl.Prepend + "-" + msg)
}
type A1 struct {
Logger
}
type A2 struct {
Logger
}
func (a A2) Log(msg string) { // Overriding implementation
fmt.Println("In A2")
a.Logger.Log(msg) // Call the original interface value!
}
func main() {
a := A1{ConsoleLogger{"A1"}}
b := A2{ConsoleLogger{"A2"}}
a.Log("Test")
b.Log("Test")
}

Related

Generic approach and recommendation how to remove dependency

I have a question regarding dependency injection.
Please consider the example below.
For example, selector() is a function that select something and guarantee return an interface
In this example
bar.node.go
type NodeTemplate struct {
Name string
}
// satisfy interface declared in db.foo.go
//but never imports anything from db.foo.go
func (node *NodeTemplate) GetUuidName() string {
if node != nil {
return node.Name
}
return
}
db.foo.go
// interface declared in db.foo.go
type Node interface {
GetUuidName() string
}
Option A
// So selector receives a map of Some interface and populate a map
func SelectSomething(nodemap map[string]Node, selectFactor string) {
// selection from db and result populate in a map
}
Option B
Another pattern SelectSomething return a Node
and it Interface
So another package will depend on importing Node
and that will introduce a dependency.
func SelectSomething(seleconsomething) []*Node {
// do selection and return a slice of SomeInterface
n := &Node{} // here it need to be concret type T
return Node
}
So based on logic I've described I see the first approach is better but in that approach, select need do concrete type allocation in order to populate a map.
Consider another example
db.foo.go
type Node interface {
GetUuidName() string
}
func inserter(node *Node) error {
// do some work
node.GetUuidName()
}
For a case like in inserter case, inserter has no external dependency, inserter just needs to receive something that satisfies the interface. Declare interfaces locally and that brake a dependancy.
But in the case of selector example, it has to do memory allocation in order to return or populate a map or return something that has concrete type T. So in both case, it has to have internal re-presentation.
So here is my question can selector somehow at run time figure out a type it receives based on the interface and instantiate an object of that type and insert to a map as an interface or return a slice of the interface. ?
By doing so selector function will have no dependancy on what it receives it just guarantee it will instantiate the same object type T
and return interface.
or can selector return interface but I guess I have to have a bi-directional interface between db package and package X or dynamic dispatcher need to do some magic ?
You want a type to behave in a certain way. That is achieved via an interface. This case is no different. Simply add the desired behavior to your interface, as demonstrated below with the Foo interface.
package main
import (
"fmt"
"reflect"
)
type Foo interface {
Bar()
TypeOf() reflect.Type
}
type Baz struct{}
func (b Baz) Bar() {
fmt.Println("I am a Fooer!")
}
func (b Baz) TypeOf() reflect.Type {
return reflect.TypeOf(b)
}
func DoSomeThing(f Foo) {
f.Bar()
fmt.Println(f.TypeOf())
}
func main() {
fmt.Println("Hello, playground")
b := Baz{}
DoSomeThing(b)
}
Run on playground

Embedding of mutually dependent structures/interfaces

I have 3 structures that are similar about 70%. So I'd like to extract some common part and create some extensions with specific methods and fields.
Final structure will work as follows:
method .Start() from Common is called
Start() calls method .Name() from specific part the latter return a string
the returned result is being processed in (*Common).Process(), sometimes it should call specific's Format()
But! Specific part have to call Common part's method, for example GetVerbosity()
Like this:
package common
type Common struct {
Specificer
}
func (c *Common) Start() {
...
name := Specific.Name()
}
func (c *Common) GetVerbosity() {...}
type Specificer interface {
Name() string
Format() string
}
And specific part:
package specific1
// should implement common.Specificer interface
type Specific1 struct {
// unexported fields
}
func (s *Specific1) Name() string {...}
func (s *Specific1) Format() string {
// How to call it???
Common.Method()
}
This is similar to some frameworks - when another code calls your code, and also you call it's code.
How to implement this better? And how to create new structures?
I tried:
Embed Specific to Common, and embed vise versa:
type Common struct {
Specificer
}
type Specific1 struct {
common.Common
...
}
// But this is little bit insane:
func NewSpecific1() *common.Common {
var s = Specific1{}
return &common.Common{Specificer: &s}
}
Define 2 interfaces: Commoner and Specificer. And combined interface:
package common
type CommonSpecificer interface {
Commoner
Specificer
}
type Common struct {...} // implements all the methods from Commoner
func New() *Common {...}
//////
package specific1
type Specific1 struct { // implements all the methods from common.Specificer
Common
...
}
func NewSpecific1() *Specific1 {
c := common.NewCommon(...)
s := &Specific1{Common: c}
return s
}

Package decoupling in go

We all know dependency injection makes packages decoupled.
But I'm a little confused about best practices of dependency injection in go.
Lets assume package User needs to access Config package.
We can pass a Config object to User methods. In this way I can change the Config package functionality as long as the new code resolves the interfaces.
Another approach is call Config package methods directly , In these scenario I can change Config code too as long as the methods names remains the same. Like so
Update :
What is different between these two approaches :
package User
func foo(config ConfigObject) {
config.Foo()
}
And this one :
package User
import Config
func foo() {
config.Foo()
}
Calling config.Foo on the config argument to a method means that you receive an instance of some structure (possibly implementing interface Config) and call the method Foo on that instance/interface. Think of this as of calling a method of an object in OO terms:
package user
func foo(cfg config.Config) {
cfg.Foo()
}
Calling config.Foo having imported the config package means you are calling the function Foo of package config, not of any object/struct/interface. Think of this as pure procedural programming without any objects:
package user
import config
func foo() {
config.Foo()
}
The latter has nothing to do with dependency injection, the former may constitute a part of it if Config is an interface.
Dependency injection, on the other hand, follows generally the same rules in Go as in other languages:
accept interfaces, supply implementations
Because in Go structs satisfy interfaces implicitly rather than explicitly (as it is the case in Java)
the code accepting the value only needs to know about the interface and import it;
the code implementing it does not even need to know about the interface (it can just happen that it satisfies it);
the code that supplies the impl into a method accepting an
interface, obviously, needs to know both.
For your example this means:
package config
type Config interface {
Foo() string
}
package foo
type Foo struct{}
func (f *Foo) Foo() string {
return "foo"
}
package boo
type Boo struct{}
func (b *Boo) Foo() string {
return "boo"
}
package main
func foo(cfg config.Config) string{
return cfg.Foo()
}
func main() {
// here you inject an instance of Foo into foo(Config)
log.Print(foo(&foo.Foo{}))
// here you inject an instance of Boo into foo(Config)
log.Print(foo(&boo.Boo{})
}
Prints
2018/03/03 13:32:12 foo
2018/03/03 13:32:12 boo
Since, in my opinion, the example code given by previous poster(s) could be a bit less confusing for beginners, just by renaming things, i quickly try to do this here:
package contracts
type IConfig interface {
GetSomeString() string
}
package pkg1
type Foo struct{}
func (f *Foo) GetSomeString() string {
return "hello“
}
package pkg2
type Boo struct{}
func (b *Boo) GetSomeString() string {
return "world"
}
package main
func run(config contracts.IConfig) string {
s := config.GetSomeString()
return s
}
func main() {
foo := &pkg1.Foo{}
result1 := run(foo)
log.Print(result1)
boo := &pkg2.Boo{}
result2 := run(boo)
log.Print(result2)
// Prints: helloworld
// You learned:
// Since the run() func use a IConfig interface as
// parameter, the run() func can handle both struct
// types (Foo and Boo) as input, because both struct
// types (Foo and Boo) implement the IConfig interface.
}

Type Composition: overriding interface types

I want to compose a type of another type, but replace one of the fields (which is an interface value) with a fake. The problem I am getting is the underlying field is being used, so I can't seem to override the field.
I've demoed the problem here: https://play.golang.org/p/lHGnyjzIS-Y
package main
import (
"fmt"
)
type Printer interface {
Print()
}
type PrinterService struct {}
func (ps PrinterService) Print() { fmt.Println("PrinterService") }
type Service struct {
Client PrinterService
}
func (s Service) PrintViaMethod() { s.Client.Print() }
type FakeService struct {
Service
Client Printer
}
type SomeOtherService struct {}
func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }
func main() {
s := FakeService{Client: SomeOtherService{}}
s.PrintViaMethod()
}
Why does it print "PrinterService"? I want it to print "SomeOtherService".
Thanks.
By s.PrintViaMethod(), you are calling the promoted method FakeService.Service.PrintViaMethod(), and the method receiver will be FakeService.Service which is of type Service, and Service.PrintViaMethod() calls Service.Client.Print(), where Service.Client is of type which PrinterService, that's why it prints "PrinterService".
In Go there is embedding, but there is no polymorphism. When you embed a type in a struct, methods of the embedded type get promoted and will be part of the method set of the embedder type. But when such a promoted method is called, it will get the embedded value as the receiver, not the embedder.
To achieve what you want, you would have to "override" the PrintViaMethod() method by providing your implementation of it for the FakeService type (with FakeService receiver type), and inside it call FakeService.Client.Print().
By doing so s.PrintViaMethod() will denote the FakeService.PrintViaMethod() method as that will be at the shallowest depth where the PrintViaMethod() exists (and not FakeService.Service.PrintViaMethod()). This is detailed in Spec: Selectors.
For example:
func (fs FakeService) PrintViaMethod() {
fs.Client.Print()
}
Then the output will be (try it on the Go Playground):
SomeOtherService
See related questions and answers with more details:
Go embedded struct call child method instead parent method
Does fragile base class issue exist in Go?
Why does it print 'PrinterService'? I want it to print 'SomeOtherService'.
Because that's what your code says to do. PrintViaMethod calls s.Client.Print(), and s.Client is a (zero value) instance of PrinterService, which outputs PrinterService.
What you probably want is to call s.Print() in main(). I don't see any reason for your PrintByMethod function at all.
As per Flimzy you are calling print s.Client.Print() which is of type PrinterService implemented as receiver to Print() function printing PrinterService. You can also change type of Client PrinterService in Service struct to Someother service
package embedded
import (
"fmt"
)
type Printer interface {
Print()
}
type PrinterService struct{}
func (ps PrinterService) Print() { fmt.Println("PrinterService") }
type Service struct {
Client SomeOtherService
}
func (s Service) PrintViaMethod() { s.Client.Print() }
type FakeService struct {
Service
Client Printer
}
type SomeOtherService struct{}
func (sos SomeOtherService) Print() { fmt.Println("SomeOtherService") }
func Call() {
s := FakeService{Client: SomeOtherService{}}
s.PrintViaMethod()
}

Calling embeded struct's interface method without losing type information on the receiver

The following code fails, because after using B.Assign(A), the information on the specific type of B is lost (at least that's what I think goes wrong here):
package main
import "fmt"
type Methods interface {
Method()
Assign(Methods)
Set(Methods)
}
type Parent struct {
Methods
assigned Methods
}
type ChildA struct {
Parent
}
type ChildB struct {
Parent
msg string
}
func (this *Parent) Assign(other Methods) {
//Some other logic here
other.Set(this)
}
func (this *Parent) Set(other Methods) {
this.assigned = other
}
func (c *ChildA) Method() {
fmt.Println("I'm child A")
}
func (c *ChildB) Method() {
fmt.Println("I'm child B, and I approve this message:", c.msg)
}
func main() {
A := new(ChildA)
B := new(ChildB)
B.msg = "my message"
B.Assign(A)
A.assigned.Method()
}
Now, in order to avoid this, I would have to make another method, that has exactly the same definition as Parent.Assign(), but different receiver:
func (this *Parent) Assign(other Methods) {
//Some other logic here
other.Set(this)
}
func (this *ChildB) Assign(other Methods) {
//Same as above
other.Set(this)
}
This is rather ugly. Is there a way to preserve the information about B's type when calling the method from it's embedded struct Parent, without duplicating the code?
Is there a way to preserve the information about B's type when calling the method from it's embedded struct Parent, without duplicating the code?
No. When you call the embedded method, it is called with a pointer to the embedded struct.
Unfortunately as attractive as it first seems, embedded objects don't make Go into an object oriented language.
You might be better off just having one type with function pointers for the implementation.

Resources