シーケンスのデフォルト値

JavaFX の特徴の一つでもある シーケンス...
かなりクセがありますが、慣れてしまえば意外に便利。

と言うことで、少しシーケンスの基本をまとめておこうと思ったのですが...
結局クセの部分から書くことに...

シーケンスのクセは割と多く 一度に書くのは大変なので、取り合えず 今回はシーケンスのデフォルト値について...

シーケンス型の変数のデフォルト値が 要素を持たないシーケンス であることは 周知の事実だと思います。

例えば...

var content: Node[];
と変数を宣言した場合、content の値は要素を持たないシーケンスになります。
また、次のように変数宣言時に null で初期化しても全く同じ結果になります。
var content: Node[] = null;
null は 要素を持たないシーケンスに変換されてしまいます。シーケンスには null はないのです。

かなり違和感がありますが、こんな比較式でも true になります。

[] == null

ここまでは 想定内のお話ですが...
さらに驚くことに 実は 要素を持たないシーケンスは 型が同じであれば 全く同じインスタンス なのです。

例えば...

var s1 = [ "1" ];
var s2 = [ "1" ];

println(isSameObject(s1, s2));
の結果は もちろん false になります。この結果は世間一般の常識です。
しかし...
var s1: String[] = [];
var s2: String[] = [];

println(isSameObject(s1, s2));
の結果は違うのです。なんと true になります。
要素を持たないシーケンスのインスタンスは型ごとに一つずつしか生成されないようです。
デフォルト値が 要素を持たないシーケンスなので わからなくもないのですが...

さらに驚くことに 要素を持たないシーケンスに値を追加すると シーケンスのインスタンスがこっそりとすり替えられてしまう のです。
同じ型のデフォルト値が全て同じインスタンスである時点で当然の結果ですが...

例えば、常識的には 以下のコードのように シーケンスに 要素を追加しても シーケンスのインスタンス自体を変更している訳ではないので 当然 true になるはずなのですが そうではないのです。
以下の結果は なんと false ...

var s: String[];
var before = java.lang.System.identityHashCode(s1);

insert "Hello" into s;

var after = java.lang.System.identityHashCode(s1);

println(before == after);

つまり、シーケンスのインスタンス自体 別物になってしまっているのです。
もはや、私の常識は なんの役にも立たない...

これが本当に仕様であるなら、かなり注意しないと思わぬバグを生みそうだ。