Saturday, May 29, 2021

Sum types in Go

One thing I always missed in Go was sum types. I’ve seen some discussion before. Although Go doesn’t have this as an explicit, native feature, I found a pattern that suits my needs by defining types and interfaces.

In the example below, I simulate a function that would load application resources, which can be extracted by ID, position or a string identifier. First, we define the interface and the subtypes:

type (
	// Variant type for: ResId, ResPos, ResStr.
	Res interface{ implRes() }

	ResId  uint32
	ResPos uint32
	ResStr string
)

func (ResId)  implRes() {}
func (ResPos) implRes() {}
func (ResStr) implRes() {}

The isRes() function acts like a “tag” for each subtype.

Now, a function that receives the variant type:

func LoadResource(variant Res) {
	switch v := variant.(type) {
	case ResId:
		println("ID", uint32(v))
	case ResPos:
		println("Position", uint32(v))
	case ResStr:
		println("String", string(v))
	default:
		panic("Res does not accept a nil value.")
	}
}

Usage is now trivial:

LoadResource(ResId(2001))
LoadResource(ResPos(4))
LoadResource(ResStr("MY_ICON"))

It’s clean and it works remarkably well. I applied this technique in my Windigo library.

No comments: