This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.


14.1 – Accessing Global Variables with Dynamic Names

Usually, assignment is enough for getting and setting global variables. However, often we need some form of meta-programming, such as when we need to manipulate a global variable whose name is stored in another variable, or somehow computed at run time. To get the value of this variable, many programmers are tempted to write something like

    loadstring("value = " .. varname)()
or
    value = loadstring("return " .. varname)()
If varname is x, for instance, the concatenation will result in "return x" (or "value = x", with the first form), which when run achieves the desired result. However, such codes involve the creation and compilation of a new chunk and lots of extra work. You can accomplish the same effect with the following code, which is more than an order of magnitude more efficient than the previous one:
    value = _G[varname]
Because the environment is a regular table, you can simply index it with the desired key (the variable name).

In a similar way, you can assign to a global variable whose name is computed dynamically, writing _G[varname] = value. Beware, however: Some programmers get a little excited with these functions and end up writing code like _G["a"] = _G["var1"], which is just a complicated way to write a = var1.


A generalization of the previous problem is to allow fields in a dynamic name, such as "io.read" or "a.b.c.d". We solve this problem with a loop, which starts at _G and evolves field by field:

    function getfield (f)
      local v = _G    -- start with the table of globals
      for w in string.gfind(f, "[%w_]+") do
        v = v[w]
      end
      return v
    end
We rely on gfind, from the string library, to iterate over all words in f (where "word" is a sequence of one or more alphanumeric characters and underscores).

The corresponding function to set fields is a little more complex. An assignment like

    a.b.c.d.e = v
is exactly equivalent to
    local temp = a.b.c.d
    temp.e = v
That is, we must retrieve up to the last name; we must handle the last field separately. The new setfield function also creates intermediate tables in a path when they do not exist:
    function setfield (f, v)
      local t = _G    -- start with the table of globals
      for w, d in string.gfind(f, "([%w_]+)(.?)") do
        if d == "." then      -- not last field?
          t[w] = t[w] or {}   -- create table if absent
          t = t[w]            -- get the table
        else                  -- last field
          t[w] = v            -- do the assignment
        end
      end
    end
This new pattern captures the field name in variable w and an optional following dot in variable d. If a field name is not followed by a dot then it is the last name. (We will discuss pattern matching at great length in Chapter 20.)

With the previous functions, the call

    setfield("t.x.y", 10)
creates a global table t, another table t.x, and assigns 10 to t.x.y:
    print(t.x.y)     --> 10
    print(getfield("t.x.y"))   --> 10