六つ目の名前

date 演算の probe —— 通日、うるう境界、三万日の round-trip、すべて両 backend で参照実装と一致 —— が y0 という名のパラメータで躓いた。C backend でプログラムがコンパイルできない。y0 は libm の Bessel 関数だからだ。ひねりは、y0 が既に予約リストに載っていたこと。今回の問題はリストではなく emission パスだった —— plain な top-level カリー化関数がパラメータを raw で宣言し、body は sanitize 済みの名前を参照する。二リリース前に別のパスで直したのと同じ def/use 不一致だ。行進の六つ目の衝突にして、二種類目の故障。リストに無い名前と、リストを見ないパス。六つは、事例を数えるのをやめる数だ。

merecompilercodegendatesdogfood

probe そのものは暦の算術だった —— 月間カレンダーの先にある、日付処理の部分。Mere に date 型は ないので日付は年・月・日の tuple で、probe の中核は civil date と通日の相互変換だった。epoch からの 日数を、整数除算と剰余に強く寄りかかるアルゴリズムで計算する —— それが測ろうとしていた軸だ。probe 自体の成績は完勝だった。既知の日付の曜日は正しく出て、二つの日付の間隔は参照実装と日単位で一致し、 うるう境界を跨ぐ一日の加算はうるう年で二月二十九日を、平年で三月一日を返し、連続する三万の通日 —— およそ八十二年分 —— の round-trip は完全に逆転した。interp でも C backend でも同一に。modular 算術が 痛むだろうという事前の疑いは、少なくとも正の値域では外れた。tuple の日付はよく読めた。

y0 という名のパラメータ

摩擦は予想外の方向から来た。変換関数のパラメータは y0 と名づけられていた —— 調整済みの年、 アルゴリズム自身の提示から来る自然な名前 —— そして C backend でプログラムはコンパイルを拒んだ。 y0 は C の数学ライブラリの Bessel 関数で、backend は math ヘッダを include する。C の名前空間と 衝突した六つ目の名前だった。indexremoveacctduprun、そして今度は y0。どれも同じ やり方で発見された。普通のプログラムが、C がすでに主張していた普通の単語を使うことで。

リストに載っていて、なお壊れる

今回が違ったのは、y0 が既に予約リストに載っていたことだ。Bessel 関数群はずっと前に防御的に 追加されていた。sanitizer はその名前が危険だと知っていて、改名するはずだった —— だが plain な top-level カリー化関数のパラメータ宣言を emit するコードパスが、sanitizer に一度も尋ねなかった。 だから宣言は raw の y0 と言い、body は —— そのパラメータを返す closure に capture するとき —— sanitize 済みの綴りを参照し、C コンパイラは不一致を未宣言識別子として拒んだ。二リリース前、gzip probe がパラメータを index と名づけたとき、まったく同じ def/use 不一致が lifted 関数と closure adapter について発見され、修正されていた。これは別の扉から入ってきた同じバグだ。リストに無い名前 ではなく、リストを見ないパス。

修正は一行 —— plain パスを、他のパスが既に使っているのと同じパラメータ整形器に通す —— で、probe は どこでも緑になった。だが修正より帳簿のほうが重要だ。六つの衝突は今や二種類の故障に分かれる。 ハンドメンテのリストがまだ持っていなかった名前と、リストに相談しなかった emission パス。リストを 育てることは一つ目を直し、二つ目には何もしない。パスを監査することは二つ目を直し、一つ目には何も しない。これまでの修正はすべて事例を扱っていた。リストの隣のソースコメントは何ヶ月も前から、リストは 本質的に不完全で、robust な修正はすべてのユーザ名を名前空間化することだと認めていた —— そのたびに、 大きすぎるとして先送りされて。六つは、その先送りが慎重さであることをやめ、負債になり始める数に 感じられた。次のリリースはリストを消す。

← Back to Mere: 言語を作る