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.