2012年01月25日

Array Considered Harmful あるいは、なぜC言語のポインタは難しいのか

 大昔、子供向けのBASIC入門の本を読んだら、「配列でつまづく人が多い」と書いてあったのを覚えている。
 今でも配列――今ではたいてい「リスト」という格好いい名前がついている――を使うときには、「これこそプログラミングの味!」とでも言うべき不自然さを感じて、抵抗を覚える。
 たとえばループ変数の名前、i。なぜいつも同じ名前、つまり意味のない名前なのか。よい名前がつけられないということは、なにかがうまくいっていないということだ。
 この点で、関数オブジェクトとmapは文句なく正しい。が、それで配列まで正しくなるのか。

 
 配列とは値の集合であり、少なくとも以下の3つの性質がある。
1. 重複を許す(多重集合)
2. 要素間には前後の順序がある(全順序)
3. 配列の各要素は連続した整数と1対1対応する(インデックス)
 「プログラムでなにをしたいか」という観点から考えた場合、多重集合の性質しか使わない場合が多い。全順序は使うこともあるが、インデックスまで使うことは皆無に近い。使われない性質は余計なものであり、人を混乱させる以外なにもしていない。
 
 たとえば、財布に硬貨が総額いくら入っているか調べることを考えてみよう。
 硬貨を一枚ずつ取り出して額面を加算してゆく、というアルゴリズムを考えられないような大学生はおそらくいない。このとき財布は硬貨の多重集合であり、硬貨同士のあいだに順序はない。
 が、もし配列しかデータ構造がなければ、どうなるか。全順序でインデックスつきの奇妙な財布が出現してしまう。
 さらに、mapのない言語では、インデックスをプログラム上で使うことになる。アルゴリズム上では、硬貨を取り出す順序は偶発的なものであり、財布に備わっているものではない。ところが、もし配列しかデータ構造がなければ、硬貨を取り出す順序ばかりか、それが何番目かという数字までデータ構造に焼き込むことになる。おかしな話だ。
 
 硬貨のかわりに紙幣ではどうか。
 財布のなかの紙幣はたいてい重ねてあるので、順序がある。これならデータ構造が順序を持っていても別におかしな話ではない。重ねてある順序で紙幣を取り出すのも、必要なことではないが自然だ。しかし今度もインデックスはいらない。たとえば配列ではなくスタックでも表現できるし、そのほうが自然だ。
 
 データ構造にインデックスが必要になるのは、配列の要素が他のところから参照される場合だけだ。
 要素のIDとして考えると、インデックスの多くの性質は不要になる。連続した整数である必要はないし、そもそも整数である必要もない。だから実際、IDとしての役割はポインタや「参照」に取って代わられ、インデックスで参照するデータ構造など今ではバイナリファイルでしかお目にかかれない。
 
 配列とはおかしなものであり、高級言語の扱うべきデータ構造としては箸にも棒にもかからない欠陥品である。
 この欠陥品を、少し便利で死ぬほど厄介にしたのがC言語のポインタである。こんなものがわかるのは、配列脳の持ち主だけだろう。

Posted by hajime at 2012年01月25日 19:28
Comments
Post a comment






Remember personal info?