空白文字の増減やコメントの位置で意味が変わる話の続き

一つ前の話の続き。

世間的に知られる前の、つまりほぼベル研内部ユーザしかいなかったであろう頃の C 言語が、演算子「op=」が逆の「=op」だったはず、と思い出した。この話、最初どこで読んだんだっけかなぁ? Richie 自身の発言として読んだ記憶なんだけど(*)。今 WikiPedia みると K&R C での変更点として書いてある:

compound assignment operators of the form =op (such as =-) were changed to the form op= (that is, -=) to remove the semantic ambiguity created by such constructs as i=-10, which had been interpreted as i =- 10 (decrement i by 10) instead of the possibly intended i = -10 (let i be -10)

空白文字のことに触れていないのでこの WikiPedia 引用は伝わりにくいんじゃなかと思うがつまりこういうこと:

1 int i = 0;
2 i = -1; /* i に -1 を代入する */
3 i =- 1; /* i から 1 減算、していた、その頃の C では */
4 i=-1; /* どっち? */

もちろん皆が知る通り、現行の C 系言語の全てで、こう:

1 int i = 0;
2 i = -1; /* i に -1 を代入する */
3 i -= 1; /* i から 1 減算 */
4 i=-1; /* 疑問の余地なく i に -1 を代入 */
5 i-=1; /* 疑問の余地なく i から 1 を減算 */

その頃の C だと空白文字の増減で意味が変わり得たわけね。i=-1 を受け取ったらどう振舞ってたんだろう? 「Your brain loves ambiguousness, FU*K!」とかなんとかいって死んでたろうか、空気読んでどっちかに強制的に解釈してたろうか、あるいは親切に「坊主、そいつぁいけねぇぜ」なんて諭してたろうか。

次はコメントの話。

今圧倒的大多数の「C/C++系言語ユーザ」がもはや「知らないかもしれない」とさえ思えるほど当たり前に享受している single-line comments、これは C++ 誕生時はもちろん「C++ スタイルコメント」と呼ばれ、オリジナル C では使えなかった。さすがに「えーっ、そうだったの?」と思う人こそ稀だとは思うけれど、あまりにもどんな「Cコンパイラ」もこの形式のコメントを許容してきたから、余程の潔癖症でない限り、C 言語でも割と平気で「//」コメントを書く人はずっと前から多かった。C言語に「正式に」C++スタイルのコメントが許されたのは C99 から。

確か Scott Meyers の Effective C++ の、かなり最初の方のトピックに書かれてたと記憶してたんだけれど、違ったみたい。この2つの形式のコメントについて「混ぜるな危険」として、ちょっとイヤらしい例がどれか(Hurb Sutter の Exceptional C++ も違った)で紹介されていた。見つからないので仕方なく自力で例を編み出してみた:

1 y = x //* ... */ 2;
2 ;

「C形式コメントしか許されない世界」だとこう翻訳される:

GCC なら gcc -pedantic -ansi
1 y = x / 2;
2 ;

「C++形式コメントが許される」場合は言うまでもなくこう:

GCC なら g++ とか、-pedantic -ansi オプションなしの gcc
1 y = x
2 ;

2行目のセミコロンは、「どちらの解釈でも正当になり、その意味が異なる」例を生産するためだけに付けたものである。実際のところ一方がコンパイルエラーになるなら、大した問題とはならない。間違ったまま動くものを作れてしまうのがマズい。であるから、本当にこんなプログラムを書くような輩がいたら、それはきっと確信犯であるか、そうでないなら余程のバカか余程の天才だ。

つまるところ、「絶対に混ぜたらアカン」と強く言うほどのものは、こんなヘンチクリンな例では説得力を持ち得ないわけなんだけれども。(だいたいにして上の例はコンパイラとオプションを固定する限りは曖昧さはない。)

こういった瑣末に振り回され、そして恨んだり気に病んだりするのは実際のところは、「C/C++ プログラマ」そのものよりはむしろ、(今のワタシが Pygments の lexer を書いたりしているような)周辺ツールを作りたい人たち、である。この手の開発ツールはいつでも「言語本体で読んでいる空気を俺様にも読めってか」との闘いだったりする。

周辺ツールの充実が開発者自身の生産性に影響を及ぼすことには誰も異論は持つまい。周辺ツールを作りやすいか否かで、言語草創期の進化の速度が大きく違ってくることは、多少でもこの種のことを「作ろうとしたことがある」か「作られたものでガッカリしたことがある」かしないとなかなか実感出来ないかもしれないが、これは本当のことである。そして周辺ツールを作りにくくする最も大きな要因となりうるのがいわゆる「ヒューリスティック」(この場合「発見的手法」)に頼った処理に関係するものだ。C++ 向けツールが作りにくく、たった10年前でさえなかなか決定的な開発ツールが出来なかったのも、C++ 言語そのものが言語として複雑なだけでなく「ヒューリスティックに溢れている」から。

これは「人間さまさまの言う通り、空気読んであげるから「いいね!」よろしく」が、巡り巡れば結果として人間さまさまのためにならない、ということも意味しているのだが、多くの人々はこれを「html」(世に言う「ブラウザ戦争」)で学んだわけである。「人間のやることだから」と文法エラーをことごとく許容していったがために、「クロスブラウザ問題」という形で「htmlを書く人」も「それを読む人」も結果として苦しんだわけだ。ブラウザの開発者が「苦心して親切を実装した」ことは、あらゆる形で裏目った、てことね。

しかるに人間よ、あんまし進化しとらんのよ。C/C++ でこの種のダークサイドの芽はいくらでも観察出来たし、「html に起こってしまったこと」の教訓だって、必ずしも「おしおし、活かされてんなぁ」と思うことばっかりじゃない。何かしらの言語の再発明があるたんびに、「機械が勝手に空気読むことの功罪」について考える機会が多い。一般にヘンに空気読むよりは「ワタクシ機械はバカなんざますので、出来ないことは出来ないんだよー」に徹した方が、人間のためになることが多いのだがねぇ。

ところでせっかくnode.jsを入れたので、C/C++ からその「暗黒面」を継承している javascript で一応確認しとこうっと。C++ と同じ結果になるはずよね?

1 me@host: ~$ node
2 > x = 4;
3 4
4 > y = x //* this is comment. */ 2;
5 4
6 > 

だね。

確認してはいないけれど、java も C# も同じ結果になるんじゃないかな。最初っから両方を許しているこれらの言語では、このことは問題とはならないわけである。(けど人間にとってどうかは別。コードを読んで頭混乱する可能性は高い。)