この初版は Lua 5.0 のために書かれました。それ以降のバージョンでも概ね関連していますが、若干の違いがあります。
第 4 版は Lua 5.3 を対象にしており、Amazon やその他の書店で入手可能です。
本を購入することで、Lua プロジェクトのサポートにも貢献できます。


17.1 – メモ化関数

一般的なプログラミング技術として、スペースを時間で補う手法があります。関数の結果をメモ化して後から同じ引数で関数を呼び出すときに結果を再利用すれば、一部の関数を高速化できます。

Lua コードを含む文字列を持ったリクエストを受け付ける汎用サーバーを考えてみてください。リクエストを受け取るたびにサーバーは文字列に対して loadstring を実行し、生成された関数を呼び出します。ただし、loadstring は高価な関数で、サーバーに対する一部のコマンドは頻繁に実行されます。一般的なコマンドが "closeconnection()" のように繰り返し何度も loadstring を呼び出す代わりに、サーバーは補助的なテーブルを使用して loadstring からの結果をメモ化できます。loadstring を呼び出す前、サーバーはテーブル内の文字列にすでに変換があるかどうかを確認します。文字列が見つからなかった場合(その場合のみ)、サーバーは loadstring を呼び出し、結果をテーブルに格納します。この動作を新しい関数にまとめることができます

    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

このスキームでは、かなりの節約になります。ただし、予期しない無駄が生じる可能性もあります。コマンドによっては何度も繰り返されるものがありますが、ほとんどのコマンドは一度しか発生しません。徐々にテーブル results には、サーバーがこれまで受信したすべてのコマンドとそのそれぞれのコードが蓄積されていきます。時間が経つと、サーバーのメモリが枯渇します。弱参照テーブルは、この問題に対する簡単な解決策です。テーブル results の値が弱ければ、ガベージコレクションサイクルごとにその時点で使用されていないすべての変換が削除されます(つまり、事実上すべてのことです)

    local results = {}
    setmetatable(results, {__mode = "v"})  -- make values weak
    function mem_loadstring (s)
       ...    -- as before
実際、インデックスは常に文字列であるため、必要に応じてテーブルを完全に弱くすることができます
    setmetatable(results, {__mode = "kv"})
最終結果はまったく同じです。

メモ化テクニックはオブジェクトの一意性を確保する場合にも役立ちます。たとえば、フィールド redgreenblue がある何らかの範囲を持つテーブルとして色を表すシステムがあるとします。ナイーブなカラーファクトリーは新しいリクエストごとに新しい色を生成します。

    function createRGB (r, g, b)
      return {red = r, green = g, blue = b}
    end
メモ化テクニックを使用すると同じ色に同じテーブルを再利用できます。各色の一意なキーを作成するには、セパレーターを間に挟んで色インデックスを連結するだけです。
    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
この実装における興味深い結果として、ユーザーは原始型の等価演算子を使用して色を比較できることが挙げられます。なぜなら、2 つの共存する等しい色は常に同じテーブルで表されるからです。場合によっては、ガベージコレクターのサイクルにより results テーブルがクリアされるため、同じ色が異なるテーブルで表される可能性があることに注意してください。ただし、特定の色が使用されている限りは、results から削除されません。したがって、ある色が新しい色と比較されるのに十分な長さ生き残ると、その表現も新しい色によって再利用されるのに十分な長さ生き残ることになります。