Golang struct composition - composed with struct cannot access its "parent" - go

This question appears to be a duplicate of Can embedded methods access "parent" fields?, but it is not in the sense that I know that there is no way to access the "parent" fields; I am just looking for suggestions on another way to do this, because I like the idea of the Pausable struct.
I am trying to make a convenience struct that enables other structs to receive some pausing/unpausing methods.
Imagine the following:
Pausable struct
type Pausable struct {
isPaused bool
}
func (p *Pausable) Pause() {
p.isPaused = true
}
func (p *Pausable) Unpause() {
p.isPaused = false
}
Struct that composes with Pausable
Now on my other struct I want to overwrite the Unpause() method, so that besides changing the value of p.isPaused some other stuff happens as well.
type Mystruct struct {
Pausable // Composition
}
func (s *Mystruct) Unpause() {
s.Unpause()
// Do other stuff
}
Problem
The problem becomes this. I want to add an PauseUntil() method to the Pausable struct, so that it becomes
type Pausable struct {
isPaused bool
}
func (p *Pausable) Pause() {
p.isPaused = true
}
func (p *Pausable) Unpause() {
p.isPaused = false
}
func (p *Pausable) PauseUntil(dur time.Duration) {
p.Pause()
go func() {
time.Sleep(dur)
p.Unpause()
}()
}
When the timeout runs out, however, Unpause() is called on Pausable, and not on Mystruct. What would be a clever way around this?

You could make PauseUntil a function that operates on a Pauser interface.
E.g.
type Pauser interface {
Pause()
Unpause()
}
func PauseUntil(p Pauser) {
p.Pause()
go func() {
time.Sleep(dur)
p.Unpause()
}()
}
Then you should be able to pass your myStruct to that function:
ms := new(myStruct)
PauseUntil(ms)

Related

How to Implement Inheritance pattern in Go [duplicate]

How to implement an abstract class in Go? As Go doesn't allow us to have fields in interfaces, that would be a stateless object. So, in other words, is it possible to have some kind of default implementation for a method in Go?
Consider an example:
type Daemon interface {
start(time.Duration)
doWork()
}
func (daemon *Daemon) start(duration time.Duration) {
ticker := time.NewTicker(duration)
// this will call daemon.doWork() periodically
go func() {
for {
<- ticker.C
daemon.doWork()
}
}()
}
type ConcreteDaemonA struct { foo int }
type ConcreteDaemonB struct { bar int }
func (daemon *ConcreteDaemonA) doWork() {
daemon.foo++
fmt.Println("A: ", daemon.foo)
}
func (daemon *ConcreteDaemonB) doWork() {
daemon.bar--
fmt.Println("B: ", daemon.bar)
}
func main() {
dA := new(ConcreteDaemonA)
dB := new(ConcreteDaemonB)
start(dA, 1 * time.Second)
start(dB, 5 * time.Second)
time.Sleep(100 * time.Second)
}
This won't compile as it's not possible to use interface as a receiver.
In fact, I have already answered my question (see the answer below). However, is it an idiomatic way to implement such logic? Are there any reasons not to have a default implementation besides language's simplicity?
The other answers provide an alternative to your problem, however they proposed solution without using abstract classes/struct, and I guess if you were interested in using abstract class like solution, here is very precise solution to your problem:
Go plaground
package main
import (
"fmt"
"time"
)
type Daemon interface {
start(time.Duration)
doWork()
}
type AbstractDaemon struct {
Daemon
}
func (a *AbstractDaemon) start(duration time.Duration) {
ticker := time.NewTicker(duration)
// this will call daemon.doWork() periodically
go func() {
for {
<- ticker.C
a.doWork()
}
}()
}
type ConcreteDaemonA struct {
*AbstractDaemon
foo int
}
func newConcreteDaemonA() *ConcreteDaemonA {
a:=&AbstractDaemon{}
r:=&ConcreteDaemonA{a, 0}
a.Daemon = r
return r
}
type ConcreteDaemonB struct {
*AbstractDaemon
bar int
}
func newConcreteDaemonB() *ConcreteDaemonB {
a:=&AbstractDaemon{}
r:=&ConcreteDaemonB{a, 0}
a.Daemon = r
return r
}
func (a *ConcreteDaemonA) doWork() {
a.foo++
fmt.Println("A: ", a.foo)
}
func (b *ConcreteDaemonB) doWork() {
b.bar--
fmt.Println("B: ", b.bar)
}
func main() {
var dA Daemon = newConcreteDaemonA()
var dB Daemon = newConcreteDaemonB()
dA.start(1 * time.Second)
dB.start(5 * time.Second)
time.Sleep(100 * time.Second)
}
If this is still not obvious how to use abstract classes/multi-inheritance in go-lang here is the post with comprehensive details. Abstract Classes In Go
If you want to provide a "default" implementation (for Daemon.start()), that is not the characteristic of an interface (at least not in Go). That is a characteristic of a concrete (non-interface) type.
So Daemon in your case should be a concrete type, conveniently a struct since you want it to have fields. And the task to be done can be either a value of an interface type, or in a simple case just a function value (a simple case means it would only have one method).
With interface type
Try the complete app on the Go Playground.
type Task interface {
doWork()
}
type Daemon struct {
task Task
}
func (d *Daemon) start(t time.Duration) {
ticker := time.NewTicker(t)
// this will call task.doWork() periodically
go func() {
for {
<-ticker.C
d.task.doWork()
}
}()
}
type MyTask struct{}
func (m MyTask) doWork() {
fmt.Println("Doing my work")
}
func main() {
d := Daemon{task: MyTask{}}
d.start(time.Millisecond*300)
time.Sleep(time.Second * 2)
}
With a function value
In this simple case this one is shorter. Try it on the Go Playground.
type Daemon struct {
task func()
}
func (d *Daemon) start(t time.Duration) {
ticker := time.NewTicker(t)
// this will call task() periodically
go func() {
for {
<-ticker.C
d.task()
}
}()
}
func main() {
d := Daemon{task: func() {
fmt.Println("Doing my work")
}}
d.start(time.Millisecond * 300)
time.Sleep(time.Second * 2)
}
An easy solution is to move daemon *Daemon to the argument list (thus removing start(...) from the interface):
type Daemon interface {
// start(time.Duration)
doWork()
}
func start(daemon Daemon, duration time.Duration) { ... }
func main() {
...
start(dA, 1 * time.Second)
start(dB, 5 * time.Second)
...
}
You can implement abstract class in go.
The definition:
type abstractObject interface{
print()
}
type object struct{
a int
abstractObject
}
Now object is an abstract class, like java's.
You can inherit it and use its members:
type concreteObject struct{
*object
}
(o *concreteObject) print() {
fmt.Println(o.a)
}
func newConcreteObject(o *object) {
obj := &concreteObject{object: o}
o.abstractObject = obj // all magics are in this statement.
}
And use the object with concreteObject's methods:
o := &object{}
newConcereteObject(o)
o.print()
And cast abstract object to concrete object:
concObj := o.abstractObject.(*concreteObject)
Just like other OOP languages.
The solution by Max Malysh would work in some cases if you don't need a factory. However the solution given by Adrian Witas could cause cyclic dependencies issues.
This is the way I achieved implementing an abstract class the easy way respecting cyclic dependencies and good factory patterns.
Let us assume we have the following package structure for our component
component
base
types.go
abstract.go
impl1
impl.go
impl2
impl.go
types.go
factory.go
Define the definition of the component, in this example it will be defined here:
component/types.go
package component
type IComponent interface{
B() int
A() int
Sum() int
Average() int
}
Now let's assume we want to create an abstract class that implements Sum and Average only, but in this abstract implementation we would like to have access to use the values returned by the implemented A and B
To achieve this, we should define another interface for the abstract members of the abstract implementation
component/base/types.go
package base
type IAbstractComponentMembers {
A() int
B() int
}
And then we can proceed to implement the abstract "class"
component/base/abstract.go
package base
type AbstractComponent struct {
IAbstractComponentsMember
}
func (a *AbstractComponent) Sum() int {
return a.A() + a.B()
}
func (a *AbstractComponent) Average() int {
return a.Sum() / 2
}
And now we proceed to the implementations
component/impl1/impl.go // Asume something similar for impl2
package impl1
type ComponentImpl1 struct {
base.AbstractComponent
}
func (c *ComponentImpl1) A() int {
return 2
}
func (c *ComponentImpl1) A() int {
return 4
}
// Here is how we would build this component
func New() *ComponentImpl1 {
impl1 := &ComponentImpl1{}
abs:=&base.AbstractComponent{
IAbstractComponentsMember: impl1,
}
impl1.AbstractComponent = abs
return impl1
}
The reason we use a separate interface for this instead of using Adrian Witas example, is because if we use the same interface in this case, if we import the base package in impl* to use the abstract "class" and also we import the impl* packages in the components package, so the factory can register them, we'll find a circular reference.
So we could have a factory implementation like this
component/factory.go
package component
// Default component implementation to use
const defaultName = "impl1"
var instance *Factory
type Factory struct {
// Map of constructors for the components
ctors map[string]func() IComponent
}
func (f *factory) New() IComponent {
ret, _ := f.Create(defaultName)
return ret
}
func (f *factory) Create(name string) (IComponent, error) {
ctor, ok := f.ctors[name]
if !ok {
return nil, errors.New("component not found")
}
return ctor(), nil
}
func (f *factory) Register(name string, constructor func() IComponent) {
f.ctors[name] = constructor
}
func Factory() *Factory {
if instance == nil {
instance = &factory{ctors: map[string]func() IComponent{}}
}
return instance
}
// Here we register the implementations in the factory
func init() {
Factory().Register("impl1", func() IComponent { return impl1.New() })
Factory().Register("impl2", func() IComponent { return impl2.New() })
}
The functionality of abstract class has below requirements
1. It should not be possible to create direct instance of abstract class
2. It should provide default fields and methods.
A combination of interface and struct can be used to fulfill above two requirements. For example we can see below
package main
import "fmt"
//Abstract Interface
type iAlpha interface {
work()
common(iAlpha)
}
//Abstract Concrete Type
type alpha struct {
name string
}
func (a *alpha) common(i iAlpha) {
fmt.Println("common called")
i.work()
}
//Implementing Type
type beta struct {
alpha
}
func (b *beta) work() {
fmt.Println("work called")
fmt.Printf("Name is %s\n", b.name)
}
func main() {
a := alpha{name: "test"}
b := &beta{alpha: a}
b.common(b)
}
Output:
common called
work called
Name is test
One important point to mention here is that all default method should have iAlpha as first argument, and if default method needs to call any unimplemented method they they will call on this interface. This is same as we did in common method above - i.work().
Source: https://golangbyexample.com/go-abstract-class/

How to test dependency has been called correctly

In Go, how would I test that a mock dependency has been called in the correct way.
If I have a struct that takes a interface for a dependency, after injection I want to be able to test the original mock object has been called.
My current code in this example I can not see that the struct value has changed. If I change my code to pass by reference it triggers the error:
s.simpleInterface.Call undefined (type *SimpleInterface is pointer to interface, not interface)
type SimpleInterface interface {
Call()
}
type Simple struct {
simpleInterface SimpleInterface
}
func (s Simple) CallInterface() {
s.simpleInterface.Call()
}
type MockSimple struct {
hasBeenCalled bool
}
func (ms MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
I see three easy ways to fix this:
1- Change the signature of the Call method to receive a pointer to MockSimple, and when instantiating the Simple struct, give it the address of your mock:
func (ms *MockSimple) Call() {
ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: &ms,
}
s.CallInterface()
if ms.hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
2- Not the cleanest solution, but still works. Use it if you really cant use #1. Declare "hasBeenCalled" somewhere else and change your MockSimple to hold a pointer to it:
type MockSimple struct {
hasBeenCalled *bool
}
func (ms MockSimple) Call() {
*ms.hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
hasBeenCalled := false
ms := MockSimple{&hasBeenCalled}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
3- Probably a really bad solution: using globals, so I would only use it as a last resort (always avoid global state). Make "hasBeenCalled" a global and modify it from the method.
var hasBeenCalled bool
type MockSimple struct{}
func (ms MockSimple) Call() {
hasBeenCalled = true
}
func TestMockCalled(t *testing.T) {
ms := MockSimple{}
s := Simple{
simpleInterface: ms,
}
s.CallInterface()
if hasBeenCalled != true {
t.Error("Interface has not been called")
}
}
Cheers!

Effectively wrapping public sdk types in golang

I am using pagerduty go sdk to do a bunch of api requests.
Particularly I am making use of
func NewClient(authToken string) *Client
to create a new Client type. I want to add some utility functions to my own work to *Client. I tried doing this:
type BetterPdClient *pagerduty.Client
func NewClient(auth string) BetterPdClient {
return pagerduty.NewClient(auth)
}
func (b *BetterPdClient) DoSomething() {
b.GetIncident(....)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
pd_client.DoSomething()
}
But I get the following error:
invalid receiver type *BetterPdClient (BetterPdClient is a pointer type)
I understand that DoSomething() is expecting a pointer as caller. Only other way I could think of is sending the ptr as a function argument:
func NewClient(auth string) *pagerduty.Client {
return pagerduty.NewClient(auth)
}
func DoSomething(cl *pagerduty.Client) {
fmt.Println(cl)
}
func main() {
pd_client := NewClient("")
fmt.Println(pd_client)
DoSomething(pd_client)
}
Is there a better way?
Declaring a type as a pointer to another type is almost never what you want because Go doesn't allow you to add methods to that new type, nor to the pointer of that type as you've already figured out yourself. This one doesn't compile either:
type T struct{}
type P *T
func (P) M() {}
If you want to "extend" a type without "hiding" it's existing functionality your best bet is to embed it in a struct.
type T struct{
// ...
}
func (T) M() {}
type U struct {
*T
}
func NewU() *U {
return &U{&T{}}
}
func (U) N() {}
func main() {
u := NewU()
u.M()
u.N()
}
And what I mean by "hiding existing functionality" is that when you define a new type in terms of another, already existing type, your new type will not get direct access to the methods of the existing type. All you're doing is just saying that your new type should have the same structure as the already existing type. Although it's worth pointing out that this property gives you the ability to convert one type to the other...
type T struct{
// ...
}
func (T) M() {}
type U T
func NewU() *U {
return &U{}
}
func (U) N() {}
func main() {
u := NewU()
u.M() // compile error
u.N()
// convert *U to *T and then call M
(*T)(u).M()
}

Collections of generic structs with embedded locks in golang

Below I have an example of one structure which embeds another. I'm trying to figure out how to pass the more specific structure pointer to be stored in a less specific one. You can think of it as a collection. Wrapping in an interface doesn't seem to work, as doing so would make a copy, which isn't valid for structs with locks. Ideas?
package stackoverflow
import "sync"
type CoolerThingWithLock struct {
fancyStuff string
ThingWithLock
}
func NewCoolerThingWithLock() *CoolerThingWithLock {
coolerThingWithLock := &CoolerThingWithLock{}
coolerThingWithLock.InitThingWithLock()
return coolerThingWithLock
}
type ThingWithLock struct {
value int
lock sync.Mutex
children []*ThingWithLock
}
func (thingWithLock *ThingWithLock) InitThingWithLock() {
thingWithLock.children = make([]*ThingWithLock, 0)
}
func NewThingWithLock() *ThingWithLock {
newThingWithLock := &ThingWithLock{}
newThingWithLock.InitThingWithLock()
return newThingWithLock
}
func (thingWithLock *ThingWithLock) AddChild(newChild *ThingWithLock) {
thingWithLock.children = append(thingWithLock.children, newChild)
}
func (thingWithLock *ThingWithLock) SetValue(newValue int) {
thingWithLock.lock.Lock()
defer thingWithLock.lock.Unlock()
thingWithLock.value = newValue
for _, child := range thingWithLock.children {
child.SetValue(newValue)
}
}
func main() {
thingOne := NewThingWithLock()
thingTwo := NewCoolerThingWithLock()
thingOne.AddChild(thingTwo)
thingOne.SetValue(42)
}
Error: cannot use thingTwo (type *CoolerThingWithLock) as type
*ThingWithLock in argument to thingOne.AddChild
It's impossible to store the wrapping type in []*ThignWithLock since go has no notion of structural subtyping.
Your assertion that an interface will result in copying is incorrect, and you can get the desired effect by doing:
type InterfaceOfThingThatParticipatesInAHierarchy interface {
AddChild(InterfaceOfThingThatParticipatesInAHierarchy)
SetValue(int)
}
type ThingWithLock struct {
...
children []InterfaceOfThingThatParticipatesInAHierarchy
}
func (thingWithLock *ThingWithLock) AddChild(newChild InterfaceOfThingThatParticipatesInAHierarchy) { ... }
As long as the interface is implemented on a *ThingWithLock and not ThingWithLock, there will be no copying of the receiver struct itself, only the pointer to the struct will be copied on the stack.

golang: how is "func() interface {}" and "func() *MyStruct" incompatible types?

Suppose I have code, where a function accepts another one as an argument:
type Person struct {
Name string
}
func personBuilder() * Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback func() interface {}){
fmt.Print(callback());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This results in error cannot use personBuilder (type func() *Person) as type func() interface {} in function argument. If I change personBuilder return type to interface{}, it works, but in real project I'm working on I want to have a concrete type for clear design and TDD purposes.
Does Go support such method signature generalization? What are the workarounds, if you could not change the personBuilder part (e.g. you have a lot parameterless functions that return different type of struct, and you want to build a consumer function that accepts any of those builders as argument)?
One workaround is to define an inline function that calls personBuilder.
printRetrievedItem(func() interface{} {return personBuilder()});
Playground
You can create an interface with a method that returns an interface{}:
type Thinger interface {
Thing() interface{}
}
func (p *Person) Thing() interface{} {
return p
}
func printRetrievedItem(t Thinger){
fmt.Print(t.Thing());
}
func doStuff(){
printRetrievedItem(personBuilder);
}
This is just an example, please use a better name!
To answer your question, fun() A is not a func() interface{}, for the same reason that []A is not an []interface{}. It's explained very well in the go wiki.
Either do a wrapper like #GrzegorzŻur suggested or define your own interface and make your xxxxBuilder return it:
type Namer interface {
Name() string
}
type Person struct {
name string
}
func (p *Person) Name() string {
return p.name
}
func personBuilder() Namer {
return &Person{name: "John"}
}
func printRetrievedItem(callback func() Namer) {
fmt.Printf("%T: %v", callback(), callback().Name())
}
You can use pkg reflect for this. (Note however that the solution of #OneOfOne is more idiomatic).
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
}
func personBuilder() *Person {
return &Person{Name: "John"}
}
func printRetrievedItem(callback interface{}) {
vals := reflect.ValueOf(callback).Call([]reflect.Value{})
fmt.Println(vals[0].Interface())
}
func main() {
printRetrievedItem(personBuilder) // &{John}
printRetrievedItem(func() string { return "hello" }) // hello
}
Here's an example in the playground.

Resources