Southclaws
Southclaws

Reputation: 1940

Composition combining data and functions with interfaces and structs

I'm wondering if this is something that's done in Go or if I'm thinking about it all wrong: composing type x interface and type x struct so my interface methods have access to specific data too:

The C programmer in my wants to do this:

type PluginHandler interface {
    onLoad()
    pm *PluginManager
}
func (ph PluginHandler) onLoad() {
    pm.DoSomething()
}

There I have an interface defined with a function, but also some data I want to pass to those functions but this is a syntax error.

So is this something that's doable in Go through some other method or am I just thinking about the problem wrong?

Upvotes: 2

Views: 2611

Answers (3)

Kaveh Shahbazian
Kaveh Shahbazian

Reputation: 13523

Just for the record, you can add extra methods to an existing type, by introducing another (indirection) type as:

type HandlerManager PluginManager

func (x *HandlerManager) onLoad() {
    ((*PluginManager)(x)).DoSomething()
}

And if you need to go with a more generic solution, a combination of Adapter & Strategy patterns could do:

type PluginHandlerAdapter struct{ _onLoad func() }

func (x *PluginHandlerAdapter) onLoad() {
    x._onLoad()
}

Used like (public/private access ignored):

type PluginManager struct {
    PluginHandlerAdapter
}

func NewPluginManager() *PluginManager {
    res := new(PluginManager)
    res._onLoad = res.DoSomething
    return res
}

Upvotes: 0

Jonathan Hall
Jonathan Hall

Reputation: 79734

TL;DR; There is no direct translation to Go.

Long answer:

Go interfaces are only methods.

Go structs are only data (with the possibility of receiver methods).

You can reference, and even embed interfaces within structs:

type Frobnicator interface {
    Frobnicate() error
}

type Widget struct {
    Frobnicator
    WidgetName string
}

But that's not really what you're talking about.

The best answer to your dilema is, I believe: Take a step back. You're focusing on the trees, and you need to look at the forest. Go takes a different approach than C, or classical OO languages like C++ and Java.

Look at the general problem to be solved, and find solutions to that in Go. This can be a painful process (I can say from experience), but it's really the only way to learn the new way of thinking.

Upvotes: 1

abhink
abhink

Reputation: 9136

You have defined onLoad incorrectly. You cannot define a function directly on interface type.

Once you have an interface, you need another type to implement methods specified in the interface. For example, if another type implements onLoad method, they automatically (implicitly) implement the interface PluginHandler.

The other thing you need to do is change the interface function type to accept the required data:

type PluginHandler interface {
    onLoad(*PluginManager)
}

struct SomeType {
    // ...
}

func (s SomeType) onLoad(pm *PluginManager) { // SomeType now implements
    pm.DoSomething()                          // PluginHandler interface.
}

This way, you get to inject whichever PluginManager required by PluginHandler.

Also, you can use SomeType as a PluginHandler type whereever required.

func someFuntion(ph PluginHandler) {
    // ...
    ph.onLoad(pm)
    // ...
}

Can be called with an input argument of type SomeType:

s := SomeType{}
someFunction(s)

Upvotes: 2

Related Questions