Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a preferred way to design signal or event APIs in Go?

Tags:

go

I am designing a package where I want to provide an API based on the observer pattern: that is, there are points where I'd like to emit a signal that will trigger zero or more interested parties. Those interested parties shouldn't necessarily need to know about each other.

I know I can implement an API like this from scratch (e.g. using a collection of channels or callback functions), but was wondering if there was a preferred way of structuring such APIs.

In many of the languages or frameworks I've played with, there has been standard ways to build these APIs so that they behave the way users expect: e.g. the g_signal_* functions for glib based applications, events and addEventListener() for JavaScript DOM apps, or multicast delegates for .NET.

Is there anything similar for Go? If not, is there some other way of structuring this type of API that is more idiomatic in Go?

like image 651
James Henstridge Avatar asked Dec 18 '12 07:12

James Henstridge


4 Answers

I would say that a goroutine receiving from a channel is an analogue of an observer to a certain extent. An idiomatic way to expose events in Go would be thus IMHO to return channels from a package (function). Another observation is that callbacks are not used too often in Go programs. One of the reasons is also the existence of the powerful select statement.

As a final note: some people (me too) consider GoF patterns as Go antipatterns.

like image 140
zzzz Avatar answered Oct 29 '22 14:10

zzzz


Go gives you a lot of tools for designing a signal api.

First you have to decide a few things:

Do you want a push or a pull model? eg. Does the publisher push events to the subscribers or do the subscribers pull events from the publisher?

If you want a push system then having the subscribers give the publisher a channel to send messages on would work really well. If you want a pull method then just a message box guarded with a mutex would work. Other than that without knowing more about your requirements it's hard to give much more detail.

like image 25
Jeremy Wall Avatar answered Oct 29 '22 15:10

Jeremy Wall


I needed an "observer pattern" type thing in a couple of projects. Here's a reusable example from a recent project.

It's got a corresponding test that shows how to use it.

The basic theory is that an event emitter calls Submit with some piece of data whenever something interesting occurs. Any client that wants to be aware of that event will Register a channel it reads the event data off of. This channel you registered can be used in a select loop, or you can read it directly (or buffer and poll it).

When you're done, you Unregister.

It's not perfect for all cases (e.g. I may want a force-unregister type of event for slow observers), but it works where I use it.

like image 4
Dustin Avatar answered Oct 29 '22 15:10

Dustin


I would say there is no standard way of doing this because channels are built into the language. There is no channel library with standard ways of doing things with channels, there are simply channels. Having channels as built in first class objects frees you from having to work with standard techniques and lets you solve problems in the simplest most natural way.

like image 2
Sonia Avatar answered Oct 29 '22 15:10

Sonia