何物でもない値

Lua でテーブルを使ったコード書いてると、しばしば、
「特定のフィールドを予め確保しておきたい」状況に出くわします。


例えば __index や __newindex をカスタマイズした場合に、
それらを無視してフィールドにアクセスする場合、普通は rawget/rawset を使うわけですが、
インデックスアクセスと rawget/rawset は、どちらが高速か? - 野良C++erの雑記帳で書いたように、
実は rawset/rawget をするより、普通にテーブルアクセスしたほうが高速らしいのです。


またそれ以外にも、テーブルの配列部分に「穴」があるといろいろ問題があったり、
とにかく、 nil という値は Lua の中で特別扱いされすぎていて、若干使いにくいです。


じゃあ nil じゃなくて false を使えばいいじゃないか、とも考えましたが、
確かに if not x とか書けるので混乱は少ないので悪くないですが、
やはり論理値は論理演算の結果であるという意味的に、どうなのかな、と。


で、そういう場合に、一意なタグがあると便利だな、ということで、
一意なタグを生成する関数 generate_tag なんてもんを作ってみました:
http://ideone.com/gvyJ8

-- 一意なタグを作る
do
  -- メタテーブル
  local mt
  do
    local error = error
    local function index_error()
      error( "attempt to index a tag", 2 )
    end
 
    mt = {
      __index     = index_error,
      __newindex  = index_error,
      __metatable = "tag"
    }
  end
 
  -- 本体
  local setmetatable = setmetatable
  function generate_tag()
    local t = {}
    setmetatable( t, mt )
 
    return t
  end
end
 
local none = generate_tag()
 
t = { none }
print( #t ) -- 1
print( t[1] == none ) -- true
 
-- error!
none.a = x

だから何。

追記

C API を使っていいなら、

int generate_tag( lua_State* L )
{
  lua_newuserdata( L, 1 );
  return 1;
}

これでおっけーです。無駄なテーブルとか必要ないので省メモリですね!