バグの原因を要約すると以下の二つ:
eqv?
が循環構造のあるレコードを受け取るとSEGVを起こす。equal?
がレコードの中身を比較する(R6RS的には規格違反)
eqv?
がレコードの中身をチェックするのは、実はR6RS、R7RS両方で規格違反なのだが(明確にアドレス比較のみと書いてある)、equal?
を変更した際にR6RSのテストスイートを通すために必要だったという経緯がある。(テストケースの意味もよく分からないんだけど、フィールドの存在しないレコードはコンストラクタが同一のオブジェクトを返してもいいってことなのかなぁ?)1.に関してはレコード周りを取り除いてしまえば直るのは明白だったのだが、2.との兼ね合いでどうしようかなぁとい感じになるもの。そもそも、
eqv?
が中身を見るというのはいろいろおかしい感じがするので(リストの中身とか見ないわけだし)、取り除いてしまいたい感はあった。となると2.との兼ね合いだけなんだけど、これ自体はもともと便利だからという理由で入れてあっただけなので、正直取り除いてもそんなに影響ないだろうと思っていた。実際R7RS的には未規定なわけだし。が、SRFI-116に落とし穴が潜んでいた。SRFI-116はイミュータブルなリストを定義しているんだけど、その参照実装のテストケースが
equal?
にレコードの中身を検査することを要求するコードになっていた。参照実装はChibiとChickenの2つの処理系で動くように実装されているのだが、どうもこの2つはレコードの中身を見るみたいである。新しいSRFIだからまだ使ってる人は少ないだろうし、暗黙的な要求なので無視しても問題ない気はしたのだが、人気処理系のうちの二つでやられているのなるとなぁという気持ちの方が大きかった。じゃあどうしたか?実装をR6RSの
equal?とそれ以外という風に分けた。ポータブルなコードを書くという上ではR6RSの方がより細かく規定してあるのでいいのだろうけど、これくらいの処理系拡張は許して欲しいという気持ちもある。そうすると実装を二つにする以外に方法が思いつかなかったのだ。ということで、(rnrs base)
と(scheme base)
で定義されているequal?
は別物になった。この動作に依存したコードを書くというのはあんまりないと思うけど、ハッシュテーブルをequal?
で作ってキーにレコードを使用している場合は影響がでるという話。
No comments:
Post a Comment