アプリケーションハンガリアン

2020年2月14日

ジョエル・スポルスキーの過去のブログによると、ハンガリアン記法が世界中のプログラマーから嫌われるようになったのは、一つの誤解が元になっているのだそうです。続けて、特定の種類のハンガリアン記法には今もなお価値があるのだとも述べられています。この主張は今ではある程度受け入れられ、その種の記法はアプリケーションハンガリアンと呼ばれるようになりました。

あなたのプログラムで、アプリケーションハンガリアンは使われていますか? もしないのなら、これを導入できる箇所がどこにありそうか、改めて検討してみるとよいかもしれません。そのことは取りも直さず、人間特有の弱さに思いを巡らせるよい機会にもなるからです。

単位が違うものをプレフィックスで区別する

私は高校の物理の授業で、「計算が正しいかどうかは単位に注目するとよい」と教わったことがあります。私はこの教えを今でも大事にしています。プログラミングも完全に同じだからです。人間というのは、掛けるべきところで割ったり、割るべきところで掛けたりといったミスをしょっちゅう犯すものです。

人はまた、似て非なるものを混同して取り扱ってしまう性向があります。いわゆる「取り違え」というやつです。ある国ではポンドとニュートンを取り違えたせいで、火星探査機が軌道に乗らなかったという失敗があったそうです。

このような間違いを防ぐためにも、私はプレフィックスによる単位の明確化を強く推奨しています。以下にコード例を示します。

const double hertzCpuClock = 200.0e+6F;

void wait(double secTimeout)
{
  FRC older = getFreeRunningCounter();
  while (true)
  {
    FRC newer = getFreeRunningCounter();
    double secElapsed = (newer - older) / hertzCpuClock;
    if (secElapsed > secTimeout) { break; }
  }
}

このルールを徹底すれば、次のことを観点にコードレビューすることで、第三者でも計算の確からしさが検証できるようになります。

  • 加減乗除の結果としての単位に矛盾はないか
  • 初期化・代入の両辺の単位は同じか
  • 関数名とその戻り値の単位は同じか
  • 単位が違うもの同士で加減算していないか
  • 単位が違うもの同士を比較していないか

単位が同じものをプレフィックスで区別する

実は厳格な単位があればまだ幸せで、本当に恐ろしいのは単位だけで表現できないもののほうです。これらはなまじ単位だけに頼ると、かえって間違った道を突き進むこともあるため、特に注意が必要です。

無次元量

無次元量とは、SI 単位系(時間・長さ・質量・電流・温度・物質量・光度)の掛け合わせで表現できないもの、あるいは相殺されてしまうもののことです。比や角度、ビットやバイトなどの情報量が、その代表例です。無次元量には便宜上の単位が付くことがほとんどですが、これらはしばしば隠れて見えることがあるため、プレフィックスによる強い意識づけがなおさら重要になってきます。

無次元量は、個数、人数、カウント値、エンコーダ値など、挙げ始めるときりがありません。これらのうち、互いに混同しやすいものがあれば、それを防ぐための新たなプレフィックスを考案するとよいでしょう。

写像関係

写像関係とは、一方から他方へ、特定の関数によって(その逆は逆関数によって)変換しなければならない関係にあるものです。これらは、たとえば摂氏と華氏のように、違う単位で呼び分けられることもありますが、そうとは限らないのが厄介です。たとえば私が取り扱ったプログラムでは、次のようなものがありました。

  • 電圧:実効値と波高値
  • 座標:座標変換前と座標変換後
  • 時刻:協定世界時(UTC)と日本標準時(JST)

これらはたとえ同じ単位でも互いに交換不可能ですから、プレフィックスによる明確な区別が必須となります。

点と線

プログラムに登場する値には時々、それが「点」なのか「線」なのかを意識しないと危ないものが含まれています。たとえば次に挙げるものは、それぞれが同一軸上の点と線の関係にあることがわかりますか?

  • 時刻と時間
  • 位置と距離
  • 電位と電圧
  • 高度と高低差

なぜ危ないかというと、単位だけに注目すると二つは同じに見えるからです。プログラムの中にこのような点と線の関係にあるものが含まれていないか、よく検討してみてください。もしあれば、独自のプレフィックスを考案するのも手ですが、このケースに限っては、値そのものをクラスでラップするほうが得策かもしれません。