unendlich - Home About Archive

Enumerations in Lua

Posted on 22.07.2016

Lua is a programming language that, in the best Scheme tradition, takes pride in its extreme simplicity. But it takes things even further in one aspect: There is just one data structure, the associative array, or map. As Lua was designed from the beginning to be an extension language that could be picked up easily by non-programmers, this makes sense. And Lua’s usage numbers show this strategy worked. Lua is widely used as a scripting language for computer games, for instance.

In Lua maps are called tables. Although having tables as the only data structure in the language seems very limiting at first, the language has several features to help using tables in several different contexts. This post will be about enumerations in Lua.

In languages such as C and Java, enumerations are written like this:

enum Colors {
   BLUE = 1,
   GREEN,
   RED,
   VIOLET,
   YELLOW
};

The enumeration values are stored as integral types. The integer values can be assigned manually for one or more values, the remaining ones will get successive integers. The values can be used as integers, such as for indexing arrays.

In Lua it is possible to use a similar syntax, based on one of the several table constructors:

Colors = {
   BLUE = 1,
   GREEN = 2,
   RED = 3,
   VIOLET = 4,
   YELLOW = 5,
}

-- the above is equivalent to:
Colors = {
   ["BLUE"] = 1,
   ["GREEN"] = 2,
   ["RED"] = 3,
   ["VIOLET"] = 4,
   ["YELLOW"] = 5,
}

-- reading the integer back
local color = Colors.RED     -- the same as Colors["RED"]

This already goes some way to making our enumeration, but it’s not very convenient because we need to assign integers to every key in the table. If that’s not good enough a different table constructor could be used but the keys would need to be written as strings explicitly:

Colors = {
   "BLUE",
   "GREEN",
   "RED",
   "VIOLET",
   "YELLOW",
}

-- which is equivalent to:
Colors = {
    [1] = "BLUE",
    [2] = "GREEN",
    [3] = "RED",
    [4] = "VIOLET",
    [5] = "YELLOW",
}

Now items are numbered automatically but the keys and values are inverted. In this case we would need a helper function to switch those for us:

-- assumes the tbl is an array, i.e., all the keys are
-- successive integers - otherwise #tbl will fail
function enum(tbl)
    local length = #tbl
    for i = 1, length do
        local v = tbl[i]
        tbl[v] = i
    end

    return tbl
end

When passing a literal table (or string) to a function in Lua the parentheses can be omitted which lets us create a handy DSL:

Colors = enum {
   "BLUE",
   "GREEN",
   "RED",
   "VIOLET",
   "YELLOW",
}

-- finally, get our integer from the enum!
local color = Colors.RED

As a side note, strings in Lua are immutable and interned by the interpreter, which means that accessing tables by string keys is very fast. In the table implementation the pointer to the interned string will be used instead of a hash function for looking up the associated values. This is not as fast as accessing an enumeration value in C, but in the interpreted world, it’s still very fast.