Skip to content
Sword

Enums

A set of named integers, with a type of its own:

import "std/io"
enum Kind u8 {
None
Bool
Text = 9
Real
}
func describe(k Kind) string {
switch k {
case Kind.None:
return "nothing"
case Kind.Bool:
return "a flag"
case Kind.Text:
return "a string"
case Kind.Real:
return "a number"
}
}
func main() !int {
try io.Print(describe(Kind.Text))
return 0
}

Look at what is not in that switch: a default. It is not needed, and that is the point of naming the set. A switch over an enum with no default has to cover every member, so the function returns on every path and the compiler knows it. Add a member later and every switch that has stopped being complete tells you where:

error: this switch over Kind does not cover Bytes
note: add the missing cases, or a 'default'

The width is optional — enum Kind u8 above, enum Kind for the default int. A member with no value continues from the one before, starting at zero, so Real is 10.

The type is its own, which is the other half of the bargain. k + 1 does not compile, and neither does passing a Kind where an integer is wanted. Crossing over is written out:

byte := u8(Kind.Text) // 9
back := Kind(9) // Kind.Text

The second one is not checked against the members — there is no table at run time to check it against — which is what makes it usable for a value that just came off a socket.

Printing one gives the member’s name, because the number would tell you nothing:

import "std/io"
enum Kind u8 {
None
Bool
Text = 9
}
func main() !int {
k := Kind.Text
try io.Printf("{} is {}, and {}\n", k, u8(k), nameof(Kind.None))
return 0
}

nameof(k) asks for the name on its own, and gives the empty string for a value that is not a member.