Stricter Go enums with go-genums

Sep 18, 2015 · 3 min read

Go has an idiomatic way to declare enums, that is by many (me included) praised for its simplicity:

type Day intconst (
Monday Day = 1 + iota

Other languages have usually more features for enum types, for example in Java:

public enum Day {

And then you can use features like:

for (Day day: Day.values()) {
if (day == Day.Monday) {
System.out.printf("Monday is day number %d\n", day.ordinal());
System.out.printf("Day of the week: %s\n", day);

In C# you can benefit from similar type-safety checks, and a slightly different syntax for the base type:

enum Days : byte {Monday=1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

Let’s give now another look at the same enum in Go, with focus on what we could make use of:

type Day int // a String() method for each value, so that we can printf it during development/logging?const (
Monday Day = 1 + iota // more complex types maybe?
// boundary check so that I cannot inadvertently create an 8th day of the week?
// array/slice of allowed values?

In a discussion with other Go coders I came up with the idea of using a slightly stricter syntax for Go enums, (ab)using type switches and the marvels of templating (with go:generate), the result of which is the go-genums project.

The generated code for this weekdays example with go-genums is (some parts redacted for simplicity):

package main

// *** generated with go-genums ***

// DayEnum is the the enum interface that can be used
type DayEnum interface {
String() string
Value() dayEnum

// dayEnumBase is the internal, non-exported type
type dayEnumBase struct{ value dayEnum }

// Value() returns the enum value
func (eb dayEnumBase) Value() dayEnum { return eb.value }

// String() returns the enum name as you use it in Go code,
// needs to be overriden by inheriting types
func (eb dayEnumBase) String() string { return "" }

// ... [redacted declaration of a type+methods for each allowed enum value]

var internalDayEnumValues = []DayEnum{

// DayEnumValues will return a slice of all allowed enum value types
func DayEnumValues() []DayEnum { return internalDayEnumValues[:] }

// NewDayFromValue will generate a valid enum from a value, or return nil in case of invalid value
func NewDayFromValue(v dayEnum) (result DayEnum) {
switch v {
case daySunday:
result = Sunday{}.New()
case dayMonday:
result = Monday{}.New()
case dayTuesday:
result = Tuesday{}.New()
case dayWednesday:
result = Wednesday{}.New()
case dayThursday:
result = Thursday{}.New()
case dayFriday:
result = Friday{}.New()
case daySaturday:
result = Saturday{}.New()

// ... [redacted]

The resulting generated enum code is nonetheless longer and more complex, but you do not have to type it as it’s auto-generated; among the features added by this code generation step, the one I personally like most is the possibility to use type switches for enum evaluation:

day := Monday{}.New()switch day.(type) {
case Monday:
fmt.Println("It's", day)
panic("It's not Monday!")

Note here that a type switch over an interface value is still pretty efficient, as it will not de-reference the actual value (be it an int or a large struct) but rather use Go’s internal type id.

Last but not least, with go-genums you can use structs for your enum declaration and auto-generated validating factory methods, and you do not loose the capability of directly comparing enum variables; you can read more and play around with it at the github project page.

Where do we Go now

8-bit adventures in Linux-land, with Go & other geeky…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store