「void tRrLM(); //ボイド・テラリウム」の謎
2020年1月23日に、日本一ソフトウェアさんから「void tRrLM(); //ボイド・テラリウム」という名のゲームが発売されるらしい。著名なベンダさんなのできっとゲームも面白いに違いない。軽く公式の紹介を見る限りではオーソドックスな「不思議のダンジョン」形式のようで、古い祖先をたどれば NetHack や Rogue にたどり着く系譜だ。NetHack は昔のゲームなだけにとっつきにくく高い難易度を誇るが、今でも存分に遊べる完成度の高いゲームである。
おっと、話が逸れた。ここは Qiita である。したいのはゲームの内容の話ではない。だいたい執筆時点では発売すらされていない。
そう、したいのはタイトルの話である。
タイトルから推測されること
このゲームのタイトルを見て、誰かが言った。
「なんか副作用のあるメソッドみたいなゲームあるなぁ」
違いない。この表記はゲーム名としては異質である。そして我々エンジニアにとってはれっきとした意味を成す。
さて、実際このタイトルを見て思うことはなんだろう? 個人的にはこうだった。
- C 言語の流れを汲んだ構文である
- 関数の本体は記述されていない
- 無理な短縮が行われた命名である
- 戻り値と引数から副作用が期待される関数である
ここから考えられることを見ていこう。
プロトタイプ宣言である
前述 1「C 言語の流れを汲んだ構文である」、2「関数の本体は記述されていない」から、これは恐らく C 言語のプロトタイプ宣言である。Java や C# など C の流れを汲んだ言語もあるが、もしこれらなのだとすれば、関数本体が定義されるか、抽象メソッドであることを示す abstract
宣言がなされなければならない。それがないということは、ほぼ間違いなく C 言語のプロトタイプ宣言とみて良いだろう。
ところで最近の言語しか知らない人にとっては、プロトタイプ宣言とはなんぞや、という話もありそうだ。見ての通り関数の入力と出力のみを記述し、本体を持たない宣言である。古き C の時代はファイルごとに上からコンパイルし、あとでリンクする方式でプログラムをビルドしていた 1。このため他のファイルに存在する関数を呼び出す場合、そのファイルを「知らなくても」関数を呼び出すコードを生成する必要があり、その呼び出しコード生成のために関数の中身がないプロトタイプ宣言を行っていたのだ。実体は別のファイルに存在し、リンク時にひとつの実行ファイルにまとめられる。
逆に言えば関数の呼び出しは中身を知らなくてもその形式だけ分かれば行える。これは示唆的である。プログラミングにおける関数とは入力と出力だけが明らかなブラックボックスでもあるのだ。
組込用の専用コンパイラ用である
そして 3, 4 から組み込み用の専用コンパイラのための記述である可能性が考えられる。もちろんこれらはどちらも決定的な内容というわけではない。ただ単に、そう考えるとつじつまが合うというだけだ。
まず 3 「無理な短縮が行われた命名である」について。もちろん現代言語でもこういった名前を付けられないというわけではない。ただしこのような分かりづらい関数名を付与することは推奨されないし、通常はしないだろう。だが昔の組込用専用コンパイラのためのコードだとするとこうなってしまう理由が見えてくる。そういった場面ではリソースが少なく、コンパイラ自身も貧弱で識別子の長さに制限がかけられているものもあったのだ。だから今のように分かりやすく長い名前を付けることができなかったのである。
と偉そうに語っているが実のところ伝聞である。そういう世界もあったんだよという話を聞いたことがある程度で真偽のほどは定かではない。
とはいえ、仮に識別子の長さに制限があるとすれば、各々の識別子が極めて短いのも納得がいく。恐らくチップやピンの名前なんかもアルファベット数文字で表していたのだろう。こうして考えていくとだんだんこの関数名の謎も見えてくる。
そして 4「戻り値と引数から副作用が期待される関数である」。当然別に今もこういった関数やメソッドを定義することになんの制限もないわけだが、やはりあまり推奨される形式ではない。しかしこれも同様に古い時代の組み込みプログラミングだとすると、そもそも複雑な関数呼び出し自体に制限があったとしても不思議ではないと考えられる。もっと原始的な仕組み、つまり特定のメモリアドレスに値を書き込み、チップを駆動させる命令を送り、そしてどこかのメモリアドレスの値が変わる、そんな仕組みだったと考えるとつじつまが合う。もしかしたら音が鳴ったり、どこかのモーターが回ったり、 LED ランプが点灯したりするのかもしれない。
唯一気になるのが一行コメント形式 //
である。古い時代の C ではこれはコメントとして認められなかった。仕様として導入されたのは C++
や C99
からである。とはいえ、仕様として制定される前から大抵の処理系でこの形式のコメントは実装されていたわけで、該当専用コンパイラも独自に実装していたのだろう。たぶん。そういうことにしよう。
予想されるコード
これらの推測から実際の用例も考えてみよう。奇抜な名前をしているように見えるが、前述の話を考慮に入れて冷静に見ていくとなんとなく見えてくるものがある。 R
L
M
は恐らく別のチップなどと通信を行うためのメモリアドレスなのだ。こうしてみると Left
Middle
Right
なのかもしれない。いかにもそれっぽい。
となると関数名も読み解ける。きっと to R read L M
の省略形なのだ。こうなってくると類似品の void tLrRM();
とか void tMrL();
とかがあるに違いないと思えてくる。きっとそうだ。そうに違いない。
実際に使うときのコードはこうだ。
int *L;
int *M;
int *R;
void tRrLM(); //ボイド・テラリウム
void terrarium() {
*L = 4;
*M = 2;
tRrLM();
if (*R == 0) {
/* ... */
} else {
/* ... */
}
}
L
M
R
ポインタは初期化されていないが、なんらかの方法で具体的なメモリアドレスが割り当てられるものと思われる。そして関数呼び出しの前に該当メモリに値を書き込んでおき、関数呼び出しで外部の何かを駆動させるのだ。音が鳴るのか、 LED が光るのか、それはわからないが、何かが起きて、 R
が示すメモリの内容が変わる。これらメモリアドレスの書き込みや読み込みが、事実上の引数と戻り値なのだ。
しかしこうして眺めてみるとプロトタイプ宣言に意味不明なコメントをつけないで欲しい気持ちも出てくる。とはいえこのコメントは書いた人のお茶目であまり意味はないのかもしれない。必要とルールに従って付けた短縮名がテラリウムと読めるからなんとなく、みたいな。そもテラリウムは Terrarium なので短縮されたにしても L ではなく R のはずなのだが、まあ日本人だしね。L と R の区別がつかないのはしょうがないよね。ぼくもつかないもん。
ということで
void tRrLM(); //ボイド・テラリウム
は、なんらかの組込装置用のプログラムで使われる特殊な C コンパイラ用のプロトタイプ宣言であろう、と推測された。
というか、初投稿がこんな与太話で良いんだろうか。
-
厳密にいえば今もそうかもしれないが、あまりそういう「裏の仕組み」を気にする必要はなくなってきている。 ↩