配列など存在しない(キットラー風に)。Luaには存在しない。
配列など存在しない(キットラー風に)。Luaには存在しない。シークエンスは存在するけれど。にもかかわらず、LuaのJSONエンコーダは、テーブルをオブジェクトとしてエンコードするか配列としてエンコードするかを決定しなければならない。
典型的な問題の例を挙げよう。
{ 17, nil, 23, nil, 37, nil, 42, nil, 69 }
というテーブルが与えられたとき、どちらのJSONにエンコードされるべきだろう。
{"0":17,"2":23,"4":37,"6":42,"8":69}
だろうか?(そう、オブジェクトの名前は文字列でなければならない、JSONにおいては)
[17,null,23,null,37,null,42,null,69]
だろうか?
おそらく、後者だろう。しかし、いったいどうして?
問題を整理しよう。
シークエンスは存在する。しかし、シークエンスをJSON配列として扱うべきかどうかは判らない。
setmetatable({ [666] = 42 }, { __len = function () return 666 end })
は配列として扱われるべきだろうか。
判らない。
LuaのJSONエンコーダは、だからおそらく、疎密という概念を導入した。疎なシークエンスはオブジェクトとしてエンコードし、密なシークエンスは配列としてエンコードする。
最大の添字が要素数の二倍、これが判定基準(のひとつ)である。魔法の数字。しかし、いったいどうして?
最大の添字がmであり、要素数がnであるようなテーブルを考えよう。簡単のためにmが1以上9以下だとすると、オブジェクトとしてエンコードした場合のオーバーヘッドは
n * 4
文字ぶんである。これは各要素に、たとえば添字が2の場合に
“2”:
という名前を付けなければならないから(ここではmが一桁だと仮定している)。配列としてエンコードした場合のオーバヘッドは
(m - n) * 5
文字ぶんである。これは存在しない要素について
null,
を挿入しなければならないから。つまり、オブジェクトとしてエンコードしたほうが配列としてエンコードするよりも文字数が少なくなる条件は
n * (9 / 5) < m
となる。つまり、最大の添字が要素数の1.8倍よりも大きな場合ということ。最初に挙げた問題の例はちょうどこの場合になっている。もちろん、mの桁数が増えれば、オブジェクトとしてエンコードした場合のオーバーヘッドは増えていく。もちろん、ここでは人間の《思い》は論じられていない。
人間の《思い》なんて窓から投げすてちまえ!
(このようなrationaleはどこかに書かれているはずだけれど、私は見つけられなかった)