Lakshan Perera

Learning Go - Constants & Iota

When you learn Golang, your first encounter with constant declarations can be little confusing.

type ByteSize float64
const (
    _ = iota  // ignore first value by assigning to blank identifier
    KB ByteSize = 1<<(10*iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)

Why only the first constant (KB) has a value assigned? What does iota means? These are some of the questions that could pop into your mind when you go through the above code sample for the first time. As I mentioned in the previous post, best way to find answers to such questions is to refer the Go spec.

Constant Expressions

In Go, constants can be numbers, string or boolean values. Basically, constant values can be represented by a literal(eg. "foo", 3.0, true) or by an expression(eg. 24 * 60 * 60). Since constants are initiated at the compile time, constant expressions should be composed only from constant operands.

If a constant value is a literal or evaluated from an expression containing only untyped constant operands it is an untyped constant. If you want, you can explicitly specify a type for a constant at the time of declaration.

const typed_size int64 = 1024
const untyped_size = 1024

var f float64 = typed_size // will give you a compile error
var f float64 = untyped_size // valid assginment

As shown in the above example, if you try to assign a typed constant to a variable of a different type it will give a compilation error. On the other hand, an untyped constant is implicitly converted to the type of variable at the assignment.

Declaring Constants

You can declare multiple constants in a single line as a comma-separated list. However, you should always have same number of identifiers and expressions. This means,

 const a, b, c = 1 //invalid assignment

is invalid.

You should write it in this way:

 const a, b, c = 1, 1, 1 //valid assignment

If you feel this is too repetitive, you can try the parenthesized form of constant declaration. Most interesting property of parenthesized form is you can omit an expression to an identifier. If you do so, the previous expression will be repeated. So the above example can be re-written in parenthesized form like this:

 const(a = 1
       b
       c
      )

Here constants b and c will also take the value 1.

const (
    Yes = 1
    True
    No = Yes >> 1
    False
)

In the above example, constants Yes and True gets the value 1; while No and False gets 0. Also, note that we can use a previously defined constant in an expression to declare another constant.

What is Iota?

A practical usage of constants is to represent enumerated values. For example, we can define days of the week like this:

const (
  Sunday = 0
  Monday = 1
  Tuesday = 2
  Wednesday = 3
  Thursday = 4
  Friday = 5
  Saturday = 6
)

Iota is a handy shorthand available in Go that makes defining of enumerated constants easy. Using iota as an expression, above example can be re-written in Go as follows:

const (
  Sunday = iota
  Monday
  Tuesday
  Wednesday
  Thursday
  Friday
  Saturday
)

Iota value is reset to 0 at every constant declaration (a statement starting with const) and within a constant declaration it is incremented after each line(ConstSpec). If you use iota in different expressions in the same line they will all get the same iota value.

const(
 No, False, Off = iota, iota, iota // assigns 0
 Yes, True, On                    // assigns 1
)

Finally, here's a little tricky one. What would be the value of c?

const (
    a = iota // a == 0
    b = 5    // b == 5
    c = iota // c == ?
)

In the above example, c will take the value 2. That's because value of iota is incremented at each line within a declaration. Eventhough, the 2nd line doesn't use the iota value it will still get incremented.