もう1つ■[雑記/備忘]メイヤー先生はやっぱり面白いネタを行きます。
インクリメント演算子(++)がない -- x := x + 1 と書けばいいのだから、いらない。
ここに、非常に引っかかりを感じました。
というのは、私は、インクリメント演算子(++)は必須であり、使うべきであり、使わないことこそが「悪」であると考えていたからです。
つまり、これは優れたコードなのだ §
たとえば、Cにおいて、以下のようなコードは書くべき規範的なコードと考えます。
char * pとして……。
*p++ = 式;
あるいは、char a[……]; int n;として……。
a[n++] = 式;
一方で、これをトリッキーすぎると見なして使わない主義者もいます。実際に身近にいます。
このような態度に対して、一時は「CPUのポストインクリメントのアドレッシングを活かすためには……」というような説明をしたこともありますが、メイヤー先生の主張に触れて、ふとそのような説明は自分も納得できるものではないと気付きました。
値を取得して次に進めるのは非常に原始的な基本処理である §
なぜ、*p++が許されるべきなのかといえば、値の取り出し/格納という操作と、対象となる位置の移動は、常にワンセットで実行されるべき「基本処理」であると考えるためです。
これは、私が最初にプログラム言語処理系の作り方に触れた雑誌記事に書かれた機能そのものです。これができたら、処理系は半分できたも同然……というかなり誇大な説明文が書かれていましたが、これが最も重要かつ使い回される基本処理であることは間違いないと思います。
その名をシーケンシャルアクセスという §
さて、うっかりしていましたが、この処理には昔から立派な名前があります。
つまり、「シーケンシャルアクセス」と呼ばれるアクセス方法そのものです。
「シーケンシャルアクセス」というパターンを実装するためには、値の取り出し/格納という操作と、対象となる位置の移動は、常にワンセットで実行されるべきです。
たとえば、*p++ = 式;はその条件を満たします。
しかし、*p = 式; p++;と2つに分けてしまったら、中間にいくらでも別の文を挿入でき、「シーケンシャルアクセス」というパターンを逸脱したコードをいくらでも書くことができてしまいます。つまり、*p++ = 式;は誤った書き換えによるトラブルを未然に防ぐ効能を持った良い書き方です。
しかし、ベストではない §
確かに*p++ = 式;は良い書き方ではありますが、ベストではありません。
常にインクリメント演算子を添えて記述するという制約は、プログラマの注意力に依存して実現されるものです。いともたやすく、「シーケンシャルアクセス」のパターンを逸脱する書き方ができます。
この弱点を取り除くには、(Cではできないにせよ)、ポインタや配列に対するシーケンシャルアクセスを行うクラスを用意すれば良いことになります。時間がないのでコーディング例は示しませんが、それはあり得るでしょう。
ちなみに、アクセス位置の移動(seek)という機能を持たないシンプルな「シーケンシャルアクセス」であれば、イテレータがそのものとして使用できます。
事実として、C#プログラミングでは、文字列の個々の文字に対するシーケンシャルアクセス読み出しを行うために、イテレータとforeach文を使うプログラミングを日常的に使用しています。つまり、Cならば確実に++を使っていた局面で、++を使わないプログラミングを行っているということです。
もしもシーケンシャルアクセス クラスが完備されたならば? §
もしもシーケンシャルアクセス クラスが完備されたと仮定すると、はたしてインクリメント演算子++の必須の出番はあるでしょうか?
もしかしたら無いかもしれません。
私のC#プログラミングではインクリメント演算子の出番は減っていますが、意識的にインクリメント演算子を排除していくように言語とライブラリを設計するなら、それ抜きで納得のいくコードが記述できるかもしれません。
ということを考えていると、今時のプログラム言語とライブラリには、まだまだ見直す余地があるな……と思います。
余談・インクリメント演算子の弱点の理由を問い直す §
たとえば、以下のような式の値は処理系依存であるとされます。
*p++ - *p++;
2つのインクリメント演算子がどのタイミングで、どの順序で処理されるかが明確に決まっていないためだとされます。
これは、もしかしたらインクリメント演算子を使うべきではない理由にカウントされるかもしれません。
しかし、これはフェアではないと思います。というのは、おそらく以下の式もおそらくは結果が処理系依存になると思うからです。(たぶん……そうだと思う)
getchar() - getchar();
つまり、シーケンシャルアクセスという機能性と、評価順が一定しない式表現の相性が致命的に悪いというのが真の原因であって、インクリメント演算子が悪いわけではないと思います。
たとえば、逆ポーランド法を式表現に使えば、式の評価順を一意に決めることができます。
*p++ *p++ -
と書くならば、まず"*p++"を評価して結果をスタックに積み、次に2番目の"*p++"を評価して結果をスタックに積み、"-"で2つの値をスタックから取り出して引き算を行い、結果をスタックに入れます。
このモデルを堅持している限り、順番が変わることはありません。
ナウシカさんも言っています。
"汚れているのは土(式)なんです。綺麗な土(逆ポーランド)を使えば、腐海植物(インクリメント演算子)も瘴気(不定の結果)を出さないのです。"
しかし、我々は綺麗な土には住めないのですね。残念……。(コミック版ナウシカの結末通り)
この解釈は、事実上、机上の空論です。