連想配列の同一性


奇妙な現象に遭遇したので報告。


配列へのユーティリティ的なテンプレートをいろいろ書いていたが、連想配列についてはあまり追加したいほどの機能はあまり見当たらない。連想配列は辞書的な使い方が殆どだから、挿入、取出し、検索ができれば十分なので、組込みの opIndex と、in 式、remove メソッドがあれば十分だからである。


まぁ、配列にあって連想配列にないのは dup ぐらいかなぁと思い、以下のバカみたいなテンプレートを作成。

template dup(K, V) {
	V[K] dup(V[K] map) {
		V[K] new_map;
		foreach (K key, V value; map)
			new_map[key] = value;
		return new_map;
	}
}

で、実行。

import house.tostring;
import std.stdio;

unittest {
	int[char[]] map1;
	map1["A"] = 1;
	map1["B"] = 2;
	map1["C"] = 3;

	int[char[]] map2 = map1.dup();
	map1.ToString().writefln();
	map2.ToString().writefln();
}
...
[(A:1),(B:2),(C:3)]
[(A:1),(B:2),(C:3)]

よかたい、よかたい。

値の同一性をチェックしてみよう。

	writefln(map1 == map2);

...
false

ハイ?
なんで???


あわてて、式 - プログラミング言語 D (日本語訳)の「等値式」を見てみると、

・整数かポインタは ビットパターンで
浮動小数点の場合は複雑
・クラスや構造体オブジェクトであれば、opEquals で
・静的/動的な配列の等しさは、配列の長さが等しく、かつ、全ての要素が等しければ

と書いてあるがなるほど、連想配列の等値に関する記述はない。


念のため、

template equals(K, V) {
	bool equals(V[K] lhs, V[K] rhs) {
		return (
			lhs.length == rhs.length &&
			lhs.keys == rhs.keys &&
			lhs.values == rhs.values
		);
	}
}

というテンプレートを書いて

	writefln(map1.equals(map2));

とやってみたら

true

となった。


げ〜、どう見ても等値なのだがなぁ。


これは例えば、名前やIDをキーとした、2つの辞書の等値比較ができないということになる。
2つの連想配列を大小比較するのは意味がないけど、等値比較はできた方がいいと思うがなぁ。