Representing enums in go
Tags: go, beginners, enums
Published: 2019-11-13 06:50:33

> This article will look at how to represent enums in go. It will also add some practical advice as well.

An enum is a datatype that consists of a set of named values. Many languages use the `enum` keyword to represent enum types.

# Use `iota` to define enums

According to the [Go specification](https://golang.org/ref/spec#Iota), `iota` is a keyword that **represents successive untyped integer constants** as long as those constants are in the same `constant declaration`.

For example, we can define the following set of constants from `c0 -> c2`:

```go
const (
	c0 = iota  // c0 == 0
	c1 = iota  // c1 == 1
	c2 = iota  // c2 == 2
)
```

We can **reduce the amount of code** written by removing the excess `iota` declarations:

```go
const (
	c0 = iota
	c1
	c2
)
```

The `iota` keyword also lets us define specific patterns with your constants, but in this article we are **only focusing on `enums`**.

# Applying this in practice

So let us apply this in practice. We will use the example of card suites. So we define a suite of cards:

```go
type Suite int

const (
  unknown Suite = iota
  Spades
  Hearts
  Diamond
  Clubs
  sentinel
)
```
Because our eyes are so sharp, you'd notice that I added two new values to this list: An `unknown` and a `sentinel` value. Let us work through their value.

## Using `unknown` and `sentinel` values

Within go, generally we **want our enum type to be able to support zero values**. This makes it easier to write idiomatic go without worrying about processing business logic for zero values. 

There are cases where zero values needs to be supported (e.g. for some externally defined protocol or even legacy code), but within our own application code we try to prevent it.

The purpose of the `sentinel` is to **make it easy to iterate and validate** our list of enum values. It also adds to the **maintainability of our enums**.

For example, because `Suite` is it's own type, we can in theory assign it any value. So let's try to validate that an integer is within our list of enums:

```go
func (s Suite) isValid() bool {
  return  s > unknown && s < sentinel
}
```
As you can see, our **validation code is agnostic of the specific values** of our suites. This means that we are able to add values to our enums as long as they appear `before` our sentinel value.

# Deprecating enums?

If your system is small, then this wouldn't really apply. However, suppose you do not want to support certain types for whatever reason. Go actually makes this very easy by using `_` values. So let's say that we only want to use the black `Suites`, but we need to keep the red `Suites` for historical purposes. We simply do this:

```go
type Suite int

const (
  unknown Suite = iota
  Spades
  _
  _
  Clubs
  sentinel
)

```

Using this way, we are **maintaining the `Clubs` data throughout the lifetime of our application**, and we will be able to **catch all the usages** of the red `Suite` values during refactoring.

# Conclusion

In this post we looked at how to define enums in go using the `iota` keyword with our constants. We also recommended the use of an `unknown` value and a `sentinel` value to make application programming easier. We even took a look at possibly deprecating `enum` values in our application.