十六進が読めるようになる
2 本連続の probe が、誰もが 16 進で書く数を 10 進で書いた —— SHA-256 の round 定数と Unicode 幅表 —— lexer が 0xFF を整数ゼロ + xFF という識別子として読んだからだ。それはバグでなく papercut だ: 回避は自明で、プログラムは動く。だが二度躓いた papercut はデータであり、修正は lexer の 1 分岐だ。6 リリースの一日を、全部の中で最小の変更と、papercut がいつ修正に値するかの覚え書きで締める。
Part はその中で最小の変更で締める。ここで終える意図は、その小ささこそが、到達に 6 リリース かかった理由だ、ということにある。これは papercut についての話だ: いつ無視し、いつ修正に値したか。
同じ石に、二度
papercut はバグではない。プログラムは compile し、走り、正しい答えを出す。ただ途中の何かが無駄に
ぎこちない。言語は数の lexer に一つ抱えていた: 0xFF は 16 進整数 255 として読まれなかった。整数
0 の直後に xFF という識別子、と読まれたので、それを使う行は後で「unbound variable: xFF」で
失敗した —— 原因から遠く離れた紛らわしいエラーだ。回避は自明: 手で 10 進に変換して 255 と書く。
だから長いこと誰も直さなかった。誰も 16 進リテラルを打つ理由が無かったからだ。
それからこのまさに Part で 2 本の probe が、立て続けに打った。SHA-256 には仕様書が 16 進で列挙 する 64 個の round 定数があり、それらは 10 進でコードに入った。East Asian Width 表はあらゆる表が 16 進で書く Unicode ブロック境界の列で、それらは 10 進のレンジで入った。両方動いた。両方、あるべき よりソースと照合しにくかった。コードを仕様と比べる読み手が、あらゆる数を頭の中で変換せねばならな かったからだ。1 本の probe が 16 進を 10 進で書くのは肩をすくめる話。2 本連続は測定値だ。一度躓く papercut はノイズ。二度躓く papercut は、両方リファレンスから書き写しながら、言語が本物の種類の プログラムと擦れる場所を教えている。
1 分岐と、その払い
修正は lexer の 1 分岐だ: 0 の後に x か X と 16 進数字が続いたら、16 進数字を消費して変換
する。0xFF と 0Xff はいま普通の整数として lex される —— 新しい型は無く、他の整数リテラルと
同じ backend 別の幅 —— そして 16 進数字の無い裸の 0x はまだ 0 + 識別子 x と読まれるので、
以前動いていたものは何も壊れない。8 進も、2 進も、桁区切りも無い。どれもまだ二度は要求されて
いない。目に見える払いは、それを主張した 2 本の probe にまっすぐ戻った: SHA-256 example の 64 個の
round 定数と 8 個の初期ハッシュ値はいま 16 進で、公開された仕様と行ごとに一致し、チェックサム
ツールの多項式とマスクも 16 進だ —— そして両方まだリファレンスの vector と一致する。それが変更の
論拠の全てだ: 言語がこれらのプログラムを以前は表現できなかった、ではなく、いまはそれらが写された
文書のように読める、だ。
帳簿
一日に 6 リリース、4 本の小さなプログラムから、その形ははっきり述べる価値がある。整数の幅と bitwise 演算子は問いとその答えだった —— 演算子を必要とした probe が、その下の幅問題を先に見つけた。 バイト reader とバイト writer は同じ扉の二つの半分。Mandelbrot レンダラは文書が言語に有利に嘘を ついているのを見つけ、この最後の一本は crypto と Unicode の probe が両方感じた摩擦を直した。全ての 下にあるのは一文だ: backend が 4 つある言語は実のところ、4 つの実装に同じ物語を語らせ続ける約束 であり、物語が分岐する場所を見つける最も安い方法は、まさにその一点に届く小さな本物のプログラムを 書くことだ —— ハッシュ、チェックサム、絵、テーブル —— そして各 backend が返す答えを読む。probe は 安かった。それらが比べた真実は安くなかった。方法が次にどこへ行くかは、いつものように、まだ決まって いない —— それこそが要点だ。