Interface vs. Function Reference for Listener

To support listeners, is it better is use an interface or a function reference?

I’m new to Go and I come from a Java background. Java objects often have addXXListener methods that provide callback hooks. Those hooks are interface implementations, ideally of an interface containing a single function. That’s the only choice in Java. But in C, the traditional way is using function pointers.

Go provides interfaces and function references. Both of those could be used for callback hooks. An interface has the limitation that it must be backed by an object (a struct instance). A function reference could refer to struct-backed function or a normal function. A function reference seems more flexible. Depending on how you are coding, you might not be developing in a very object-oriented way.

In any case, is there a standard way used in the API for listeners? Do people really code without objects?

2 Likes

Hi, Michael,

TL;DR: Use interfaces

Note:

I’m going to start off with a disclaimer that though I have not written code with many need for callbacks, I’m not sure whether that’s because I find alternatives or if my problem domain is just different, so your mileage may vary with my response:

I’d recommend an interface just because a lot of idiomatic Go uses interfaces. The io.Reader interface is just the following (source):

type Reader interface {
	Read(p []byte) (n int, err error)
}

It could have just as easily been implemented as a callback function, but they went with a single-member function interface because of how easy it is for types to implicitly implement interfaces.

Also, I have to disagree with you when you say:

Interfaces do not have to be backed by structs. For example:

type ReaderFunc func([]byte) (int, error)

func (f ReaderFunc) Read(p []byte) (int, error) { return f(p) }

You can see it in action here.

You see that I’m actually using just a function to implement the io.Reader interface and am using that to implement “hello world.” For this reason, you can require an interface and leave it up to implementers whether or not they want to just pass a function or a struct (or a redefined type backed by an int, string, etc.).

2 Likes

Brilliant. Thanks. I started using this pattern. It’s unfortunate that this concept isn’t built into the language.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.