配列など存在しない(キットラー風に)。Luaには存在しない。

配列など存在しない(キットラー風に)。Luaには存在しない。シークエンスは存在するけれど。にもかかわらず、LuaJSONエンコーダは、テーブルをオブジェクトとしてエンコードするか配列としてエンコードするかを決定しなければならない。

典型的な問題の例を挙げよう。

{ 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 })

は配列として扱われるべきだろうか。

判らない。

LuaJSONエンコーダは、だからおそらく、疎密という概念を導入した。疎なシークエンスはオブジェクトとしてエンコードし、密なシークエンスは配列としてエンコードする。

最大の添字が要素数の二倍、これが判定基準(のひとつ)である。魔法の数字。しかし、いったいどうして?

最大の添字がmであり、要素数がnであるようなテーブルを考えよう。簡単のためにmが1以上9以下だとすると、オブジェクトとしてエンコードした場合のオーバーヘッドは

n * 4

文字ぶんである。これは各要素に、たとえば添字が2の場合に

“2”:

という名前を付けなければならないから(ここではmが一桁だと仮定している)。配列としてエンコードした場合のオーバヘッドは

(m - n) * 5

文字ぶんである。これは存在しない要素について

null,

を挿入しなければならないから。つまり、オブジェクトとしてエンコードしたほうが配列としてエンコードするよりも文字数が少なくなる条件は

n * (9 / 5) < m

となる。つまり、最大の添字が要素数の1.8倍よりも大きな場合ということ。最初に挙げた問題の例はちょうどこの場合になっている。もちろん、mの桁数が増えれば、オブジェクトとしてエンコードした場合のオーバーヘッドは増えていく。もちろん、ここでは人間の《思い》は論じられていない。

人間の《思い》なんて窓から投げすてちまえ!

(このようなrationaleはどこかに書かれているはずだけれど、私は見つけられなかった)