 This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
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.
|  | Programming in Lua |  | 
| Part II. Tables and Objects Chapter 17. Weak Tables | 
A common programming technique is to trade space for time. You can speed up some functions by memoizing their results so that, later, when you call the function with the same arguments, it can reuse the result.
Imagine a generic server that receives
requests containing strings with Lua code.
Each time it gets a request,
it runs loadstring on the string,
and then calls the resulting function.
However, loadstring is an expensive function
and some commands to the server may be quite frequent.
Instead of calling loadstring over and over
each time it receives a common command like "closeconnection()",
the server can memoize the results from loadstring
using an auxiliary table.
Before calling loadstring,
the server checks in the table whether that string
already has a translation.
If it cannot find the string,
then (and only then) the server calls loadstring
and stores the result into the table.
We can pack this behavior in a new function:
    local results = {}
    function mem_loadstring (s)
      if results[s] then      -- result available?
        return results[s]     -- reuse it
      else
        local res = loadstring(s)   -- compute new result
        results[s] = res            -- save for later reuse
        return res
      end
    end
The savings with this scheme can be huge.
However, it may also cause unsuspected wastes.
Although some commands repeat over and over,
many other commands happen only once.
Gradually,
the table results accumulates
all commands the server has ever received
plus their respective codes;
after enough time, this will exhaust the server's memory.
A weak table provides a simple solution to this problem.
If the results table has weak values,
each garbage-collection cycle will remove
all translations not in use at that moment
(which means virtually all of them):
    local results = {}
    setmetatable(results, {__mode = "v"})  -- make values weak
    function mem_loadstring (s)
       ...    -- as before
Actually, because the indices are always strings,
we can make that table fully weak, if we want:
    setmetatable(results, {__mode = "kv"})
The net result is exactly the same.
The memoize technique is also useful to ensure the uniqueness of
some kind of object.
For instance, assume a system that represents colors as tables,
with fields red, green, and blue in some range.
A naive color factory generates a new color for each new request:
    function createRGB (r, g, b)
      return {red = r, green = g, blue = b}
    end
Using the memoize technique,
we can reuse the same table for the same color.
To create a unique key for each color,
we simply concatenate the color indices with a separator in between:
    local results = {}
    setmetatable(results, {__mode = "v"})  -- make values weak
    function createRGB (r, g, b)
      local key = r .. "-" .. g .. "-" .. b
      if results[key] then return results[key]
      else
        local newcolor = {red = r, green = g, blue = b}
        results[key] = newcolor
        return newcolor
      end
    end
An interesting consequence of this implementation is that
the user can compare colors using the primitive equality operator,
because two coexistent equal colors
are always represented by the same table.
Note that the same color may be represented by
different tables at different times,
because from time to time a garbage-collector cycle
clears the results table.
However, as long as a given color is in use,
it is not removed from results.
So, whenever a color survives long enough to be compared with a new one,
its representation also survives long
enough to be reused by the new color.
| Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |  |