新しい痛みを見つけるにはドメインを変える

四つの dogfood アプリケーションはみな同じ国に住んでいた —— 入力と出力に縛られた string と record の仕事 —— そして新しい種類の痛みを出すのをやめていた。だから次のは意図して数値にした:CSV の列にわたる統計ツール。それは新しいクラスの摩擦を即座に見つけ、最も鋭いのは浮動小数点数に infix 演算子がまったく無いことだった。修正は JSON 一家が建てられたまさにその機構を再利用し、一つの衝突は以前の修正を名前で思い出させ、そしてアークは正直に開いたまま残された縁で閉じた —— ad-hoc 多相の順序の半分、まだ建てられていない。

meredogfoodnumericoperatorslanguage-design

いまや dogfood の方法には名指す価値のある弱点があった。四つのアプリケーションが言語の粗い縁を見つける ために建てられていた —— web と database のアプリ、realtime なノートサーバ、コマンドラインのクエリ ツール、awk 的な評価器 —— そしてそれらはみな同じ国に住んでいた。そのどれもが string と record の仕事で、 入力と出力に縛られ、その算術は付随的だった。それらはその国の痛みについて徹底的で、そして静かになった、 なぜならプログラムは自分自身の形が触れる痛みしか surface できないから。新しい痛みを見つける道は四つの ような五つ目のアプリケーションを建てることでなく;まったく違うドメインに移ることで、明白な未踏の一つは 数値だった。

誰も払っていなかった税

だから五つ目の dogfood は統計ツールだった:CSV ファイルから数の列を読み、count、mean、median、最小、 最大、標準偏差を報告する。そしてそれはほとんど即座に新しい国の国境にぶつかった。浮動小数点数には、 判明したところ、infix 演算子がまったく無かった。加算とその他は prefix 関数呼び出しで、比較演算子は 整数にだけ定義され、だから二つの float の比較は型エラーだった。ツールの数値コア、算術のように読める べき部分は、代わりに関数適用の連なりのように読めた —— 走る合計は plus でなく call だった。これは数値 プログラムが払わされうる最大の ergonomic な税で、そしてそれはまったく気づかれずに来た、なぜなら以前の 四つのアプリケーションのどれも、それを感じるほどの算術を小数にしなかったから。痛みは常にそこにあった; どのプログラムもそれに傷つけられる正しい場所に立ったことがなかっただけだ。

一家を、もう一度拡張する

修正は新しい機構を要さず、それが立ち止まる価値のある部分だ。演算子を浮動小数点数で動かすことは、以前の Part が描画と JSON と等価のために建てたまさにその機構を使った:演算子を overload し、コード生成器に operand の型から正しい実装をコンパイル時に選ばせる、runtime dispatch なし、trait 宣言なしで。算術 演算子は同じコンパイル時特殊化された一家の新しいメンバに単になった —— 一つの名前、整数の振る舞いか 浮動小数点の振る舞いか、すでに知られている型で選ばれる。それらを連れてくることは、下に隠れていた潜伏 バグさえ洗い出した:整数値の浮動小数点リテラルが、コンパイラがそれを整数として読み戻す形で print されて いて、だから二つのそういうリテラルの除算が静かに整数除算だった。数値ツールのコアは、演算子が着地すると、 prefix 呼び出しが一つも残らない普通の算術として読めた。

一家を持っていた衝突

一つの摩擦は精神においてすでに解かれて到着した、なぜならそれは連載が以前に会った一家に属していたから。 標準の数学ライブラリの関数と同じ名前のヘルパ関数が、コンパイルされるとそれと衝突し、C コンパイラが 一つの名前の二つの矛盾する定義を拒んだ —— コマンドラインツールがスレッド primitive で一国前に走り 込んだシャドウイング問題のまさにその形。処置は同じだった:backend に、これらのライブラリ名も、 プログラム自身の定義に譲り邪魔にならないようリネームされねばならないと教える。再発する一家のバグを 見つけるのは気を落とすことでない。それは修正がパターンになりつつあることを意味し、パターンは二度目に 適用するほうが安い。

意図して開いたままの縁

アークの最も正直な部分は、それが完全には直さなかった痛みだ。list をソートするのは統計ツールが欲しがる 自然な次のことで、便利なデフォルトのソートは比較演算子の観点で定義されていた —— それはいまや float で 動いたが、値が具体的に型付けされたときだけ。デフォルトのソートは書かれた時点で整数の比較を焼き込んで いて、だから float の list をソートするにはまだ注釈つきの比較を手で綴る必要があった。この下にあるのは genuine に未完成のフロンティアだ:言語は形を歩いて任意の型で動く構造的等価を持つが、それに合う構造的 順序を持たない —— 構造的等価があるのと同じように record と tuple のための導出された less-than が無い。 それが ad-hoc 多相の順序の半分で、それは実で、そして建てられていない。それを平明に、隠れた縁でなく 既知の縁として名指すことが、それを残す唯一の正直なやり方で —— そしてそれを、設計を急ぐでなく残すことは、 連載がしてきたすべてと一貫している:feature はその不在を耐え難くするプログラムを待ち、注釈一つ余分で ソートできる統計ツールはまだそのプログラムでない。

五つ目の国が教えたこと

演習まるごとの教訓は方法自身についての事実だ。言語が与えるべく残した痛みは、それに対して書かれた プログラムの関数で、同じドメインの四つのプログラムはやがて言語は問題ないと合意する —— それがそうだから でなく、決して触れないものをもう感じられないから。数値に移ることが初日にまた言語を口を開かせ、それが 言ったことは四つの string ツールが決して言えなかったことだった。それはまたテーブルの上に綺麗な、名指 された問いを残した —— 構造的等価の傍らに座る構造的順序 —— それはまさに生きている言語があるべき姿勢だ。 dogfood ループはいまや五つのドメインで回され、その休息を得た、なぜなら言語が証明すべく残した次のことは どのアプリケーションについてでもまったくなかったから。それはコンパイラ自身についてで、これら五つ全部を コンパイルしてきたものが、ついに、それが一度も真に走らせたことのない一つのプログラムを正しく コンパイルできるか —— 自分自身を、だった。

← Back to Mere: 言語を作る