おがさわらなるひこのオープンソースとかプログラミングとか印刷技術とか

おがさわらなるひこ @naru0ga が技術系で興味を持ったりなんだりしたことをたまーに書くブログです。最近はてなダイアリー放置しすぎて記事書くたびにはてな記法忘れるのではてなブログに移行しました。

クリエイティブ・コモンズ・ライセンス
特に断りがない場合は、本ブログの筆者によるコンテンツは クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンスの下に提供されています。

手続き型を卒業するための言語は?

という質問を今日飲みから飲みへの移動の最中ぽろっと聞かれました。

あたしゃ一介のプログラミング言語好きなので (マニアの域には全然達していません。変態的趣味ではあるけど) まじめに答えは期待してないと思いますが不真面目に答えます。
2009.10.31 追記:アフィリエイトやってんじゃないかと思うぐらいバカバカ本のリンク張ってみました。

そもそも

なんで手続き型を卒業しなきゃいけないの?
ぶっちゃけプログラマという職業でご飯を食べていくのに、言語の潮流が手続き型でなくなる可能性は今後最低10年はないと思っていいでしょう。予想はずれたら飲み代一回ぐらいは奢ります (笑)。

ただ世界を広げるという意味では、今仕事で使っている言語とはぜんぜん違う世界に触れることは大事かもしれません。という視点で。

必須条件

変数再代入禁止。
なんでこれを禁止したいかというと、「こいつがあると手続き的にかけちゃう」から。手続き的に書いちゃうなら手続き型を使えばいいわけで、そうじゃない書き方を強制されないと意味がないでしょう。

高階関数とかを必須にしないのは、Ruby とか手続き型言語に普通に入ってるからです。


そんなわけで偏見に充ち満ちたセレクション。

セレクト1. Haskell

やっぱこれじゃないですか?
破壊代入できないし。
遅延評価もえーだし。
Real World Haskell 出たばっかりだし。あれが重いならふつける本でもいいわけだし。良書があることは学ぶべき言語を決める理由の一つになり得ます。

Real World Haskell―実戦で学ぶ関数型言語プログラミング

Real World Haskell―実戦で学ぶ関数型言語プログラミング

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

セレクト2. Erlang

言語としての成立は古いけど今でも cutting edge に面白い言語だと思う。関数型、並列、Prolog にちょっと似たユニフィケーション (パターンマッチング) 機構などなど。
本としては飛行機本でよろしいんじゃないでしょうか。

プログラミングErlang

プログラミングErlang

セレクト3. Prolog

半ば冗談半ば本気。者ども、ループすら書けなくて愕然とするがよい。うわははは。知識とルールベースを書いてくと解決できちゃうのはちょっと驚き。逆計算ができるのもステキ*1。これは関数型もそうだけど、エントリポイントが決まってないのも素敵すぎる。
でもなー、事実を書く順番で無限ループに嵌ったり、カットで枝を切りまくらないとパフォーマンスが苦しかったりするところに言語として成立させるための妥協が見えちゃうんですよねぇ。
問題は「過去の言語」と見られているせいで入門書のたぐいが払底していることですかね。今手に入る中ではこいつかなぁ。

Prologへの入門 (PrologとAI)

Prologへの入門 (PrologとAI)

洋書だとコイツ必読ってことで注文してるんですがまだ届いてませんので評価保留。
The Craft of Prolog (Logic Programming)

The Craft of Prolog (Logic Programming)

セレクト4. Scheme

破壊代入できるじゃねーか! と怒られそうですが、continuation だけですべてが許せます。読んでないけどとりあえず評判がいいのはオライリーさんの Gauche 本ですかね。岩波から出てた湯浅先生の Scheme 入門は気軽に読める点がいいと思います。手に入ればぜひ。

プログラミングGauche

プログラミングGauche

Scheme入門 (岩波コンピュータサイエンス)

Scheme入門 (岩波コンピュータサイエンス)

SICPScheme で書かれていますが、繰り返すようにあの本において Scheme は手段であって目的じゃないし、言語を学ぶために読むのはちとタフなので、私はこの点では進めません。
計算機プログラムの構造と解釈

計算機プログラムの構造と解釈

セレクトX. Scala

今ちょっと流行ってるし、TwitterRails から乗り換えたとか言ってるし、ホットな言語ではあるんだけど、オイラが言語仕様みたことないんで保留。

ところで

「新しい世界」を見たいのだったら、手続き型から離れるのではなく、[普通のプログラミング環境から離れたい」んではないのかしら?

おいらまだ勉強始めたばかりなのでなんともいえないけど、Smalltalk の世界、しかも言語としての Smalltalk じゃなくて環境としての Smalltalk、とかもすげー世界が広がると思う。あーこれがアジャイル開発の原点なのかって。
気軽に読めてけっこうしっかり書かれている(でもちょっと古い)のが

Squeakプログラミング入門―オブジェクトランドへの招待

Squeakプログラミング入門―オブジェクトランドへの招待

  • 作者: ジーン・コリエネック,菅原一孔,鈴木元,阿部和広
  • 出版社/メーカー: エスアイビーアクセス
  • 発売日: 2004/04
  • メディア: 単行本
  • 購入: 2人 クリック: 20回
  • この商品を含むブログ (12件) を見る
しっかり学びたいのであれば
自由自在Squeakプログラミング

自由自在Squeakプログラミング

SMALLTALKで学ぶ オブジェクト指向プログラミングの本質

SMALLTALKで学ぶ オブジェクト指向プログラミングの本質

ですかね。

あとそのつながりで、「コードを書かない教育用プログラミング環境」SCRATCH なんかも刺激になると思う。一見おもちゃぽいけど、普通に複数オブジェクトが非同期で動く並列プログラミングができちゃうところはプログラマはもっと注目していいと思う。
SCRATCH については和書は一冊しか出ていないので迷いようはないですね。

スクラッチアイデアブック―ゼロから学ぶスクラッチプログラミング

スクラッチアイデアブック―ゼロから学ぶスクラッチプログラミング


長々と与太話失礼しました。

*1:ただし逆計算を許す述語はトロイのでカットで切っちゃうのが普通ですが

プログラミング入門にふさわしい言語とは?【その2:職業プログラマーを目指すには】

d:id:naruoga:20091009:1255062099 に引き続き、やっと最終回*1
簡単にさらっと意見をまとめようと思っていただけなのに、なんで三回シリーズになりますか俺。文才ないな。

えー前回と話変わって、職業としてプログラマーを目指す人向けのプログラミング言語談義です。
こっちの方は前回よりもはるかに多彩な意見が存在することが予想され、私ごときではなんらかの結論を出すことはできません。ので、思いついたトピックをだらだらと語っていく形になります。
異論反論はコメントなりトラバなりはてブなりでしていただければと。

前提

大事な前提を前回書いてなかったんですが、これまでのエントリはプログラミングを学ぶ側、教える側、どっちに向いていたでしょうか。
基本的には学ぶ側も向きつつ教える側へ、という感じだったのですが、学ぶ側へ投げかけるには前提とする知識がちょいとアレでソレな気がしました。特に前回。

ので両方に色目を使うのはなしにして、

  • プログラミングを教える立場の人
  • プログラミングを自習する立場の人

に対象をしぼりたいと思います。片方向で授業を受ける立場の人は対象にしませんよ、ということです。なぜならばそういう人たちには選択肢がないわけですから(授業で教えてくれる言語以外は選びようがない)。

職業プログラマーが学ぶべき言語の要件

前回のエントリでも同様のことを述べましたが、要件の設定はこちらの方が緩くなります。「え、逆じゃないの?」と思う方もいらっしゃるかもしませんが、そーではありません。

なぜなら、職業プログラマーを目指す人間がただ一個の言語を学ぶだけで満足していいはずがないからです。ですから、ある言語では満たされていない要件が別の言語で満たされていれば十分。そのなかで、「最初の言語はなにを優先するか?」ということになります。

例によって私見ですが、考えられる要件は次のようになるのではないかと思います。

必須要件
  • 手続き型言語であること*2
  • 文法がシンプルかつ明瞭であること
  • 処理、ループ、分岐の三要素を制御構造として備えていること*3
  • 基本的なアルゴリズムやデータ構造を実現、あるいは利用できる言語であること*4
  • グローバルスコープ、ローカルスコープの概念があること
付加条件
  • オブジェクト指向言語であること*5
  • 十分に強力なライブラリ群を有すること。あるいは外部ライブラリを簡単に参照できる仕組みがあること。
  • 前記ライブラリを除き、言語単体で閉じていること。つまりテンプレート言語の類でないこと*6
  • 引数の値渡しと参照渡しが概念として明確になっていること。

よくよく考えたらまだ出てくるかもしれないですが、ひとまずこんなもので。思いついたら追記するかも……。


さてこれらを踏まえて、あとは与太話を……。

「C 言語を通っていないプログラマはダメ」は本当?

この話を書きたくてここまで来たようなもんです。

プログラミング入門言語としての C 言語

まず前提として「入門言語としての C 言語」については、正直当落線上でしょうね。
その一番の理由は、言わずとしれたポインタです。
C のポインタはアセンブラの間接参照を生で見せたようなところがあり(いや、実際そうなんですが)、なおかつそれに文字列操作やら参照渡しの機能を持たせているため、「このポインタはどのコンテキストで使われているの?」ということを常に意識しないとあっという間に混乱します。
このように、(プログラミングとして)本質的でないところで悩ませる言語は、入門に最適とは必ずしも言えないでしょう。
実力のあるメンターさんが適切なテキストを用いて、始めて C でのプログラミング入門は成り立つ、というのが私の持論です。

C を通るべきか否か、その二つの考え

「C をやらない奴はダメだ」という発言を眺めていると、二つの傾向がある気がします。

一つ目は、「俺は C でやってきた、だから今の俺がある、だから C でやるのがいいんだ」のタイプ。いや、結構多いですよ、こういう人。「SEED から見た奴はガンダム語る資格がねえ」とか「アラカン見てない奴はチャンバラ見たとはいえねえ」みたいな感じかな。
こういう人に「C で教育を行わなければいけない理由はなんですか」って聞くと「諸説有るだろうけれど、C が最高の言語の一つであることは間違いなく、だから学ばなければならない」とか答えになってないことしかいってくれないので、こういうタイプはさっくり無視しましょう。

二つ目のもっと腑に落ちる回答は「C のように資源管理を自前でやらないといけない言語を経験しないと、自分のプロセスがどれぐらいメモリを食っているかとか、そういうことを考えて設計できなくなる。だから C をやることは大事だ」というもの。うん、これなら私も分かります。
ただし、「自分のプロセスがどれぐらいメモリを食っているか、そういうことを考えて設計」しなければいけないことが必須であるならば、という但し書きをつけます。
つまり言語やプラットフォームが頑張って、GC とか階層ストレージとか使いまくって、どんだけでかいメモリを alloc しようがパフォーマンスを落とさないような環境。そんなのがあるかどうかは知りませんが、そういう環境でだけ仕事すればいいなら、資源管理なんて意識する必要ないですよね。

資源管理といえばもっと小さな例で言うと資源をオープンしたまま関数がエラーで落ちちゃってその場で return したら資源リークする。これだって ruby とかなら begin - ensuretry - finally Win32 の構造化例外と間違えた (^^;) 使えばいいわけで、これを自分で意識「しなければならない」理由は少ないと私は考えます。

ただし、C が素晴らしく有効なところ、それはコンピュータアーキテクチャを学ぶときの副読本をして見るときで、アーキテクチャの勉強がしたいなら、手段として C は必須になります。高水準言語の記法で、低水準にアクセスできるのですから。「C は高水準アセンブラ」という言葉はこういうときに生きてきます。
また Linux カーネルRuby のソースなど、C でかかれていて面白い題材はたくさんあります。こういう物に手を出すなら、当然 C は必須です。そりゃそうです、「道具」ですから。

C 言語談義まとめ
  • C をやらないプログラマはダメ、というのは幻想に過ぎないことも多いですが、資源管理を学ぶという意味では一理あります。
  • しかし資源管理を意識しなくても問題ない状況もたくさんありますし、将来に於いては資源管理を意識できないプログラマがダメである理由が消滅する可能性もあります。
    • 「C もできない奴は」という人はそういうことを念頭において発言していただきたいです。
  • ただし、C という道具を手にしていれば掘れば掘るほど金脈が出てくる、そういう分野はたくさんあります。そういう分野に手を出すために、C の知識を棚卸するのはとってもいいことだと思います。

Ruby

オイラがプログラミング言語教育でなんか一個選べ、と言われたら ruby を挙げる可能性が高いと思います。

メリットは:

  • 文法がシンプル、かつ理解しやすい。
  • クラスの数が少ない*7
  • モジュールの mix-in の考え方はわかりやすい。
  • 宣言文が少ないので、記述量が少ない。したがって理解が早い*8

10.10 追記

  • 動的型言語であり、型について意識しなくてもいいことが多いこと。
    • 別に JavaC++ のような静的型言語が悪いという意味ではないです。ただ「入門」としては、一つでも意識する必要があるものが減った方が本質が理解しやすいでしょう。

一方で、デメリットと言うか、これどうしようかな、というのが、

  • オブジェクトの考えが骨格にいるため、オブジェクト指向を早い段階で導入する必要があるが、これが悩ましい。
  • ブロックの概念もどう教えるか。IO.open のブロックとか超便利なんだけど、意味をわかりやすく説明できるかというと……。Array.each なんかもそうですね。
  • 例外も初めてのプログラミングというにはちょっと重たいか?
  • Gems とかを教えるべきかどうか。教えるとしたらどんなやり方がいいか。
    • なぜ Gems で悩むかというと、車輪の再発明をしない、というのは今のプログラマにおいて重要なスキルであると思うからです。もちろん PerlCPANPHPPear も同じ。ほしいものが有ったらまず探す。探してる手間ももったいなくてパッと作れちゃうなら作るって解もあるけど、割と手間がかかるモジュールを一生懸命実装したらもっといいのがもうありました、じゃ悲しいでしょう?
  • インスタンスメソッドやモンキーパッチングのような Ruby っぽい話を入れるかどうか。後者はともかく前者は話したい所だけど、頭がいい人なら思いついちゃうよね。んで話がそっちに引っ張られないかが心配。


なおあくまでも「プログラミングの入門」なので Rails とかは対象外です。

私なりの感触は、オブジェクトの壁さえなんとかなればいけるかなって感じです。少なくとも JavaC# で教育を行うよりかはよい効果が得られそうに感じています。理由は ruby が big class であることと宣言がないことです。少ないことと、動的型言語であることです。*9

Pascal と Modula-2 と Oberon

Pascal について知らない人はいます? いませんね? といいたいところなんだけど、もう知らない人多いんだろうなぁ。
チューリヒ工科大学 (ETH) の N. Wirth (ニコラス・ヴィルト) という人が作った教育用言語です。コンピュータの実装から離れてアルゴリズム記述をできる言語という目標を掲げた Algol ファミリー、主に Algol 60 の影響を強く受けています。

C と Pascal は対比されることが多いのでここでも C との違いを列挙してみましょう。

  • Pascal では関数は入れ子構造を持つ。
    • スコープルールも入れ子の内外で適用される。
  • Pascal は 1 パスコンパイル*10を指向している
    • したがって、前方参照 (自分の前方、ソースコード的には下の方) にある識別子 (主に関数と手続き) を参照できない。参照するためにはあらかじめ foward 文で「こういう識別子があるよ」と指定しておく必要がある。
  • 元々の言語仕様では複数ファイルへの分割は考慮されていない。
  • C ではすべて関数だが、Pascal は関数 (値を返す) と手続き (値を返さない) は厳格に区別される。関数で左辺値がないとエラーで怒られる。
  • Pascal の goto ラベルは英語一文字+数字といういかにも「使うな」という形式しか使えない。
    • また break や continue などの goto の糖衣構文も存在しない。おかげで Pascal でコード書くとフラグの嵐になる。ちょっとトホホ。
  • ポインタの使い方が厳格。基本的に「他の変数を指す」目的にしか使えない。
  • 値呼び (call by value)、参照呼び (call by reference) が文法で定義されている

太字で書いた「ポインタの使い方が厳格」「値呼び、参照呼びが文法で定義されている」の二点が、C の学習の補強として Pascal をやったほうがいい、という私の主張の源です。

C は文法を単純にすることを指向するあまり、ポインタにかなり強く依存しています。例えば:

int my_strcmp(const char *s1, const char *s2)
{
    while (*s1 != '\0' && *s2 != '\0' && *s1++ == *s2++) {
        ;
    }
    return *s2 - *s1
}

(実際にこんな関数書いたり使ったりしちゃダメだよ) みたいなコード普通に見ますよね。Pascal では文字列や配列はポインタとしてアクセスできないので上記のようなコードは書きたくても書けません。index を用意して、s1[idx1] のように書かなければなりません。まどろっこしいですが、間違いは少ないです*11

では Pascal のポインタというのはどういうときに使うかというと、いわゆるリンク構造を作るときに使います。典型的なのが線形リスト。

type
  list_cell_ptr = ^ list_cell;
  list_cell = record
                value: Integer;
                next:  ^ list_cell
              end;
  
  ...

  procedure list_add_value(var list: list_cell; value: Integer);
  var
    new_cell: cell_list_ptr;
  begin
    while list^.next <> NIL do
      list := list^.next
    new(new_cell);
    new_cell^.value = value;
    new_cell^.next = NIL;
    list^.next = new_cell
  end
  
var
  list_top : cell_list_ptr;

begin
  new(list_top);
  list_top^.value := 0;
  list_top^.next := NIL;
  add_list(list_top, 10)
end.

久しぶりに Pascal のコードを書いたので間違いもあるかもしれないし、なにせエラー処理もなにも入ってないのでマネ禁ですが、ポインタ (^) の使い方が非常に限定されていることが分かると思います。
たしか上記ソースで list_top^.next = 123 とかはコンパイルエラーで怒られるはずです。したがって C のようにメモリアクセス手段として使うことはないです *12

このように「他の構造物を指す」目的にポインタの使用を限定することで
C のような混乱を防ぐことができる理由の一つになります。

もう一つ C のいやらしいのは、基本的には値呼びしか存在せず、参照呼びをポインタで実現していることです。
例えば C で書くこういう関数は (中身は意味無しです)、

void foo(int a, int *result)
{
  *result += a;
}

Pascal ではこう書きます。

procedure foo (a: Integer; var result: Integer);
begin
  result := result + a
end

「値呼び」とは引数の「値」だけを手続き/関数に渡すことで、「参照呼び」とは引数の「参照」を手続き/関数に渡すことです。参照呼びでは引数として渡した「参照」は手続き/関数の外に波及するのがポイントです。C には参照呼びが言語仕様上存在せず、変数へのポインタを値で渡すことで無理やり参照呼びの機能を実現しています。
こいつは C++ で改善されましたが、Pascal では最初から備わっています。ので、この点でもポインタを使う必要がないのです。

ということで Pascal は今それをつかって何か応用するような言語ではありませんが、C のポインタが分からなくなったら学ぶ価値がある言語だと私は思います。
ただ、まともな処理系が少ないんですよねぇ……。GCCコンパイラファミリーに Gnu Pascal がいるのでそれを使うか、あとは Turbo Explorer の Turbo Delphi か。ただ Delphi は非常によくできた処理系ではありますが方言がきついので*13Pascal を学ぶ」というより「Delphi を学ぶ」と割り切った方がいいかもしれません。

なお Wirth はその後、モジュールプログラミングとデータ抽象を持ち込んだ Modula-2、さらにオブジェクト指向化し、Smalltalk のように環境自体をオブジェクトとして自由に操作できる Oberon という環境を作ったりしてますが、まあこういう機能については他の言語で十分学べるのでなにもこんなマイナーな言語で学ばなくてもよいでしょう。
ただし Oberon の動く環境を見たことがある人は非常にまれだと思いますので、デモしてみるとみんなに驚かれたりするかもしれませんね。

Perl/Python

なんでこの子たちが一緒になっているかというとオイラがよく知らないからです (^^;)。

Perl が強力な言語であることは認めます。しかしプログラミング言語を学ぶための教材言語としてはやや文法の自由度が高すぎるのが気になります。つまり「どうとでも書けてしまう」ので、まだ自分のスタイルが固まっていない人が学ぶのはおっかない気がするのです。特に Web 上に散乱する記号の羅列のような不可思議なコードを見ると。
それとも今は「モダン Perl 入門」読め!で済むのかし? それなら選択肢になり得るけど。いずれにせよ、回りに Perl に詳しい人がいる場合前提だと思います。独習は勧めません。

モダンPerl入門 (CodeZine BOOKS)

モダンPerl入門 (CodeZine BOOKS)

Python についてはインタプリタ iPython が強力であること、「Python チュートリアル」が非常によく書けていること*14、などなどから、なかなかいいかな、と思わなくもないですが、日本ではあまり盛んではないこと、他のオブジェクト指向言語では大抵存在するアクセス制御 (private とか public のこと) が存在しないこと、名前空間という概念がちょっと分かりにくいこと、が難点でしょうか。

Pythonチュートリアル

Pythonチュートリアル

でも Google App Engine とかで遊べるのはいいかもですね。

Smalltalk / Objective-C

もともと「自分の環境を自分で好きに触れることこそがパーソナルコンピューティング」という概念を実現するために生まれた Smalltalk

まだ私自身もかじった程度なのですが、今表示してるウィンドウにメッセージ投げるとぱっと表示が変わるとかいうのはかなり強烈な体験なので、かじってみるといいと思います。
あとオブジェクト指向言語というのは結局クラスライブラリ命なわけで、その点オブジェクトインスペクタとかが強力な Smalltalk の環境に早いうちに触れておくのは悪くないかもしれません。
ただし決して仕事に結びつく言語とはいいがたいので、最初に選ぶ言語としてどうかというとちょっと難しいですね。

Objective-CMac OS XCocoa アーキテクチャおよび iPhone/iPod Touch の開発環境として有名です。Smalltalk ほどのインタラクティブ性はないですが、言語仕様は非常に似ているので (C の名前はついているけれど C らしいところはほとんどない、そうです)、Objective-C の予習としての Smalltalk は「アリ」かもしれません。
逆に言うと Apple の環境でしかマトモに動かない (GCC には Objective-Cコンパイラも収録されてますが、フレームワークがなければ意味がないですから……) のをどう取るかですね。

Java/C++/C#

この三つを同時に論ずるなんてコイツものを知らないな、と思ったあなた、その通りです。
基本的に静的型言語、スモールクラス*15、という共通項でまとめてしまいました。乱暴なのは認めます。

えっと、Java については、あなたがプログラマとしておまんまを食べたくて、どうしても一個の言語しか勉強する時間が取れないのであれば、怪我がない選択肢だと思います。
と、なんでこんな一般論でお茶を濁すかというと、オイラ Java ぜんぜん知らないからです。Ruby とかをやってる人間からするととにかく宣言が多くてかったるいというのが印象で、もうすぐ四十郎のワタクシが覚えるのはちょっと骨。が、たぶん Ruby でご飯を食べるより Java でご飯を食べる方が簡単でしょう。PHP の方がもっと簡単じゃね? という話はともかく。

C++ は……最低でも STL、できれば Boost と一緒に勉強しましょうね。
自分でテンプレートクラスが書けるのは当然です。
もし組み込みなどの関係で RTTI 禁止、例外処理禁止、STL も禁止、と言われたら、よほどオブジェクト指向分析・設計に自信がない限り、Better C と割り切り、オブジェクト指向を忘れた方が幸せかもしれません。イケてない人の書いた C++フレームワークほど不幸なものはないからです。

C# は事情としては Java に近いかな。そのかわり MS と心中する覚悟が必要です。まあ Mono プロジェクトにコミットして NetBSD とかに Mono 移植するってことはできなかないですが。

Javascript

実用性といえばグリモンも Firefox 拡張も書けて Web 2.0 もばっちりなコイツはいい線いってると思います。
ただしオブジェクト指向の考え方に少しクセがあるので (プロトタイプ指向といいます)、そこを乗り越えるのがちょっと大変かもしれません。Prototype.js 使えって話もありますが、私は使ったことないので解説はできません。

あと Web 回りでプログラムを書くとしたら Javascript 自体よりも W3C DOM*16 を理解するというハードルが立ちはだかるので、別に Javascript だから簡単に Web 2.0 できるわけじゃないことは認識しておきましょう (^^;)。

Basic

これは完全な与太話です。
そもそも Basic という言語はダートマス大学のケメニーとカーツという二人の数学者が作った言語です。
当時は数値計算には Fortran、事務処理には Cobol、記号処理には Lispアルゴリズム記述には Algol はありましたが実用的な処理系がないという状態でした。

彼らは、数学の道具としてプログラミングを学ぶ学生たちのために、ぱっと書いてすぐ結果が得られる言語が必要であると考えたのです。一種の電卓的言語ですね。

そこで次のような思想が盛り込まれています。

  • インタプリタであること。実行の結果がその場で得られること。
  • 変数の宣言が存在しないこと。電卓を使うのにいちいち変数を宣言しない。
  • ゆえに型宣言も存在しない。後置で記号を書くことで型を示す (たしか独自型は文字列型しか存在しなかったかと)。記号がない「普通」の変数は小数型である。
  • 電卓なので大規模プログラミングの概念は最初から捨てている。のですべてグローバル変数なのは当然。スコープルールは初心者にわかりにくい。
  • 数学者が好む機能として、行列演算やグラフィカル端末を用いた場合のグラフ描画機能などを有する。

ケメニーとカーツの BasicANSI で標準化され、日本でも「JIS 標準 BASIC」として規格化されています。

これらの特徴のうち、最後のものを除いては、初期のパーソナルコンピュータ (マイコンと呼ばれていました) への移植にちょうどいい、小さくてわかりやすい文法でした。
そこでマイコンBasic のサブセットを実装するのが流行り、その一つがビル・ゲイツポール・アレンが書いて通信販売で売り、「ソフトウェアを商売にする」というビジネスモデルを確立した Microsoft Basic です。

そんなわけで初期のマイコンには大抵 MS 系の Basic がついてきて使用者が膨大になったこともあり、マイコンBasic でプログラミングを学んだ人間がよりよい言語……たとえば C や Pascal などに触れることで、「入門用にあえて切った」ところまで批判をする人間が出てきました。
曰く、構造化構文が貧弱である。
曰く、すべてグローバル変数はナンセンス。
曰く、変数を宣言しないのはバグのもとだ。
などなど……。

パソコンの分野では MS Basic と互換性を持ちながらこれらの改善を行う試みがなされました。今の Visual Basic はその完成形の一つと言えるでしょう。
しかし MS Basic との互換性を取るために堅牢な言語であることについては妥協があり、一方で文法が複雑化してしまったため、教育用言語としての Basic の精神は失われたと私は思っています。いや実際便利なときもあるのは認めますけど、VB

ダートマス大学のメンバーも黙ってこの状況をみていたわけではなく、オールドスタイルの行番号を廃止し (互換性のために使うことは許されています)、構造化構文を強化し、関数のローカルスコープを導入し、モダンな言語として再設計しました。
これが ANSI でいうところの FULL Basic、「JIS 拡張 BASIC」です。

この言語仕様に基づく処理系は True Basic として商品化されたのですが、バグバグだった上に MS Basic と互換性がなかったことが猛烈に批判され、ほとんど使われることなく姿を消しました。


この逸話から明らかなことは、

  • 教育用言語としてターゲットを絞って作った言語であっても、その言語に手慣れてしまうと、大きなプログラムを書きたくなる。
  • 言語が普及すると、そもそもの設計思想から離れ、批判を受けることがしばしばある*17
  • それがために元の思想を離れて大規模なプログラムが書けるようにすると、往々にしてそれは元の思想を生かさない形で発展する

ということです。

教育のための言語として何を選ぶべきか……難しいですね。


長々とつまらないエントリをお読みいただき、ありがとうございました。

*1:しかも書きかけで1週間近く放置してしまった。すみません。しくしく。

*2:ここ、いきなり突っ込む人がいるかもしれませんが、世の中で商売のネタになっているプログラムはほぼ間違いなく手続き型言語で書かれているので、「最初のウチに学ぶ言語」は手続き型であるべきだと思います。関数型や論理型はその次のステージでしょう。

*3:これちょっと分かりにくいですが、Fortran IV や昔の BasicDOS のバッチファイルなどで、IF 文の後ろに goto しか書けないようなのはダメ、ということです。

*4:「実現」は例えばヒープソートアルゴリズムを書けること、「利用」は qsort() が使えること、という意味で取ってください。むろん、両方できたことに越したことはありませんが、最低「実現」はできない言語はいろいろ困ります。

*5:これが付加条件かよ! という人も多そうですが、まあ、とりあえずは……。

*6:思いっきり PHP を頭にいれて書いてます。PHP を単体の言語として使うことってあまり聞かないので、単体で学ぶことに意味が薄い、という意味です。もちろん、PHP プログラマになるための職業訓練であれば話は別です。

*7:逆に言えば一つのクラスにメソッドが多いとも言えるけど。

*8:これは有名な話ですが、認知科学の知見によれば、どんなに意味の少ないものであっても(例えば宣言文とか)、行数が多い物はそれだけ理解に時間がかかると言われています。一説によれば人間が一度に認識できる要素数は 7±2 なのだそうです。

*9:宣言が「ない」わけではなくて「少ない」ですね。例えば a = Hash.new は一種の宣言とも言えるわけですから。あと動的型言語については記載漏れなので追記しました。

*10:意味わかんない人は最近新版が出た復刻されたコンパイラ」でも読んでください。雑駁に言えばソースコードを一回舐めるだけで実行コードを生成することです。 (「コンパイラ」って日本では3回出版されてるんですが今のが 2nd edition なんですよね。だから日本で昔出てたドラゴンが表紙の奴の復刻かと思ってたら、今の版は 2007 年に出た改訂版の翻訳であり、復刻というのは間違いだと指摘いただきました。)

コンパイラ―原理・技法・ツール (Information & Computing)

コンパイラ―原理・技法・ツール (Information & Computing)

*11:個人的考えでは、C/C++ でもポインタを使わずインデックスを使用する書き方にした方がよいと思います。余計にローカル変数は使用しますが、今のコンパイラなら最適化で消えるでしょう。

*12:Turbo Pascal では「メモリ配列」「I/O 配列」といって、配列にアクセスすることで実メモリや I/O にアクセスできるゴーインな機能が採用されてました。まぁ当時の Borland のこういうところは大好きですが。

*13:というより、Pascal を実用言語として使うには言語拡張せざるを得ない。

*14:ただし、純粋な入門書というより、Python はなぜこういう言語仕様になっているか、などの話もちょいちょいあるので、ちょっと「この言語がプログラミングはじめて」という人にはノイズになるかも。

*15:一個のクラスに沢山の機能を盛り込まないで、ちょっとずつ違う複数のクラスを用意するという考え方。逆は Ruby のビッグクラス。Hash や Array というコンテナクラスを考えれば思想の違いがわかりやすいと思います。

*16:この際 IE は無視。

*17:Pascal も C の設計者 Dennis Ritchie より「実用言語としては使い物にならない」とてひどい批判を受けています。

プログラミング入門にふさわしい言語とは?【その1:プログラミングの喜びを知るために】

えーとやっと本題でございます。d:id:naruoga:20091008:1255009561 はこの話題の前振りとして、自分のポジショニングを明らかにしたいというところでして。

Wassr などで周期的に話題になるこの件ですが、毎回同じことを書くのも芸がないのでここでまとめて置こうかと思いましてね。

話の発端

大きく分けて二つあります。どちらも周期的に話題に上がります。

  • 世の中には「C 言語を通っていないプログラマはダメだ」とバカにする風潮があるそうです。それは本当なのでしょうか。
  • プログラミングの入門にふさわしい言語というのは存在するのでしょうか。するとしたらその理由はなんでしょうか。

なぜプログラミングを入門するのか

そもそも話はここから始まらないといけないと思うのですが、大抵の人がすっとばしています。それはきっと無言の前提があるからだと思うのですが、当たり前とはいえ確認しておきましょう。

  1. プログラミングの楽しさそのものを教えることで、無味乾燥な道具と思われがちなコンピュータを身近に思ってもらうこと。
    シーモア・パパートの言うところの「構成主義」に基づく教育理論の一部といってもいいかもしれません。つまり与えられた知識を学ぶのではなく、自分たちで考え、物を作り、そこから得られるものこそが真の学びであるという考え。その道具としてのプログラミング。
  2. IT 分野の学徒となりたい、IT でご飯を食べたい、不幸にして? IT 業界に入ってしまった、などの理由で、プログラミングを覚えなければ将来の道が断たれてしまう。

ほとんどの人が 2. しか頭にないのではないかと思います。パパート直系の Squeak e-Toys や SCRATCH を擁する Smalltalker の中でさえ、「Non-Programmer にプログラムの喜びを教える」ということに関心を持つ人は少数派だと耳にしました。
んが、しかし、私はこれだけコンピュータが普及しネットワークがつながった今、プログラミングというあまりにも楽しいオモチャをプログラマだけが独占するのはほとんど犯罪に近いと考えているのであります。

のでまずはほとんどの人間が関心を持たないと思われる 1. から述べ、そのあとで職業としての学問*1、いやちがった、プログラミングはその次に述べたいと思います。

プログラミングの喜びを知るためのプログラミング入門言語

この観点は、先ほど述べたパパートの構成主義の実践としてのプログラミングであったり、あるいはプログラミング経験がまったくないけど Excel VBA や Notes の DB 設計を任せられたりしたアシスタントさんに対してプログラミングとはなんぞや、ということの導入にしたり、といった目的が考えられるでしょう。

求められる要件はつぎのとおりでしょう。

  • 環境作りに苦労しないこと。
  • コンパイル、リンクなどの「おまじない」が不要なこと。
  • できたプログラムが一目で面白いものであること。驚き、喜びを与えられること。
  • 直感的でわかりやすいこと。
  • 日本語のドキュメントが充実していること。
  • Windows で動作すること。
    • 可能ならば他のプラットフォームでも動作すること。

最後の要件は泣く泣く付け加えたのですが、多分非プログラマが所有している環境は圧倒的に Windows が多いだろうと思われるので……。

逆に、以下の点はさほど重要でないと思われます。

  • 作ったプログラムが実用的であること。
  • プログラムのパフォーマンスやメモリ使用量などの非機能要件。

以上を鑑みると候補は以下のようになってくるのかな、と思います。
なおこれは偏見入りまくりの私見なので、人それぞれ考え方の違いはあると思います。あらかじめご了承ください。

SCRATCH

http://scratch.mit.edu/
MIT メディアラボ発、シーモア・パパート、アラン・ケイ直系とも言える子ども教育用プログラミング環境。ソースコードを一切書かない、パレットを並べてプログラミングをするというインド人もびっくりな環境。

この連載が参考になると思います。

マウスだけでもプログラミングできる!(1):非プログラマのためのプログラミング講座
マウスだけでもプログラミングできる!(2):Scratchプログラミングの二歩目、自由な動きを付ける

この連載自体、ここで話題にしていることがまさにターゲットなので、この項目を読んでいる人にはご一読を勧めたいですが、「とにかくプログラミングの喜び、楽しさを教える」という点では大本命だと思います。

各所で行われている (関東だと川口の「メディアセブン」さん) SCRATCH を使った子ども向けコンピュータ教育の現場を後ろから見ているだけで、彼ら彼女らがどんどんプログラミングの概念を身につけていくのが分かると思うので、こういう「プログラマじゃない人のためのプログラミング教育」に興味がある人は見学してみるといいんじゃないかなぁ。


【利点】

  • インストールは簡単
  • マウスクリックだけでプログラムが可能
  • 絵や音をマウスクリックやキーボード操作で動かせるインタラクティブ性が人を惹きつける
  • 条件判定、ループなどといった概念も身につけられる
  • 公式ページによる交換、コミュニケーション
  • 電子回路やロボットとの連動が可能
  • マルチプラットフォーム対応 (Windows, Mac OS X, Linux)*2
  • @IT で連載してる (^^)

【欠点】

  • 他のプログラミング言語へのステップアップに工夫が必要
    • 見た目があまりにも他のプログラミング言語/環境と違う
    • SCRATCH はオブジェクト一つ一つにプログラムが対応する並列プログラミングなので*3、普通のシーケンシャルなプログラムとスタイルが大きく違う
  • 日本語のドキュメントはまだ発展途上かな?
    • 本は一冊出ましたけど。なかなかいい本です。買ってないけど

スクラッチアイデアブック―ゼロから学ぶスクラッチプログラミング

スクラッチアイデアブック―ゼロから学ぶスクラッチプログラミング

  • 教育事例などは増えつつ有るけどまだまだ
Squeak Etoys

http://squeakland.jp/

Smalltalk のフリーの処理系 Squeak にのっかった SCRATCH みたいな環境。というのは乱暴か。時系列的には e-Toys の方が先。
ただし Squeak の場合は最終的に Squeak の世界に降りてこられてソースをかけてしまうので、SCRATCH ほどの純粋さに欠ける気がする。

こっちの方が古いのでノウハウはたくさんあるけど (前記ページに子供向け教材とか載ってるし)、純粋に非プログラマ向けのプログラミング入門環境、という意味であれば SCRATCH の方が(僕は)いいと思うので、利点、欠点は省略します。

なでしこ

http://nadesi.com/

日本女子サッカー代表とは関係ないです。けっこう有名なので私がくだくだ書く必要はないと思いますが、「日本語でプログラムが書ける」が一番のウリでしょうね。
実はあんまり知らないので嘘書いたら誰か指摘くださいなのですが、Windows に特化して、Word/Excel との連携機能もあって、定形業務を自動化する機能を持っています。文法も(日本語であるということ以外)それほどとんがっていないので、SCRATCH などに比べると「実用的」「他の言語への移行が容易」と言えるかもしれません。一方で「日本語である」以外の驚きは少し乏しいかもしれません。

【利点】

  • インストールは簡単
  • 日本語で書ける
    • 面白い
    • 予約語などを覚えやすい
  • Windows に特化しているため、ファイル操作、Word/Excel の連携など日常業務の定形化に用いることができる
    • プログラマから取ってみれば Word/Excel が外部から自分の書いたプログラムで制御できるというのは驚きであり喜び
  • 日本で作られ育っているプログラミング言語であるので日本語のドキュメントが充実
    • 本も出てますしね。買ってないけど。

日本語プログラム言語なでしこ公式バイブル

日本語プログラム言語なでしこ公式バイブル

【欠点】

  • 「日本語で書ける」以外の面白さにやや乏しい
  • 利点の逆になってしまうが、Windows 以外のプラットフォームを考慮していない
Excel VBA

あーそこ石投げないで。
オイラもコイツがプログラミングの喜びを知るのに最高だとは思っておりません。
ただし業務上非プログラマが書く可能性の高い言語であるし、それならば、コイツでプログラミングの喜びを伝えることができるか? そのためにはなにをすればいいか? を考えることは意味があると思うのです。

こいつの場合、やはりなんといっても「普段使ってる Excel が自分の思い通りに動かせる!」ということが最大の武器でしょう。実業につながるのでつまんないっちゃそうなんですが、その驚きをどこまで引っ張ってモチベーションを維持できるかが、教える側の手腕になってくると思います。

【利点】

  • インストール不要 (Excel が入っていれば)
  • 普段使っている Excel がプログラミングの道具になるという驚き
    • データを加工してグラフ化する、などといった定型作業をしている人なら、それが自動でできることに驚いてくれるはず
  • 非常に充実したリファレンスマニュアル
  • マクロ保存機能により、手で操作した内容をプログラムに落とせる
  • Web 上にも出版物もそれこそ佃煮にするほど情報がある

【欠点】

  • あんまりエレガントな文法とは言いにくい
  • コンポーネント」という割と難しめな概念が分からないとコードが書けないのでやや敷居が高い
  • 業務とあまりにも近すぎて、最初の驚きが終わってしまうとモチベーションを維持しにくい
おがさわらなるひこ的には?

私がもし、「プログラムをまったく学んだことがない人にプログラミングを教える」なら、ぜひ SCRATCH でやってみたいと思います。

単純にプログラムの楽しさを教えるなら、SCRATCH でひたすら押し通す。
課題を与えてプログラムを作らせるんじゃなくて、「なんか作ってみてくださいよ、わかんなかったら相談に乗るから」というスタンスで。
自分のアイディアを計算機で実現することによりなにかを得るというのが「構成主義」なわけですからね。

ゴールとしてなにかの言語でプログラムをする予定が有って、その導入、ということであれば、SCRATCH は特殊なところが多々あるので、あまり長い間 SCRATCH に固執するわけにはいきません。基本概念を伝えたら他の言語に移るべきでしょう。
具体的にどの言語か、ということについては、もうちょっとプログラミングの楽しさを別の側面から見せた方がいいかな、と思えばなでしこでもいいと思いますし、いやこれでもうプログラムの経験者だ、だからプログラマとして学ぶべき言語を学ぼう、というなら私の意見としては次回エントリで書くことになると思います。

ということで

極論めいたところもありましたがお楽しみいただけましたでしょうか。
次は「プログラマになるために」と題してお送りしたいと思います。

*1:イギリスの経済学者マックス・ウェーバーの著書の名前。「プロテスタンティズムと労働の弁証法」という名著を持つウェーバーが、なぜあなたはマルクスのように行動しないのか、と学生に詰め寄られたのを、いや、学問とはそういうもんじゃない、と説いた名著。って、なんで俺こんなとこでこんな注釈してるんだろ。

*2:ただし Linux は experimental implementation だそうです。

*3:この点、プログラマの大人がもっと SCRATCH に注目していいと思う理由の一つ。

小江戸らぐ 2006 年 6 月度ミーティングに参加したよ。

東京地区の LUG (Linux Users Group) として著名な小江戸らぐ
そのゆるふわな雰囲気が前から気になっていたのですが、やっとオフ会の予定とオイラの予定があったので行ってきました。

小江戸らぐのオフは昼の部の活動報告(一月で Linux 界隈でなにをやったか) ということと、夜の部の宴会に分かれております。

昼の部では初参加ということでせっかくだからネタ披露。
もちろん印刷ネタなんだけど、Debug Hacks:

Debug Hacks -デバッグを極めるテクニック&ツール

Debug Hacks -デバッグを極めるテクニック&ツール

をせっかく買ったんだから実践したネタ(まあ、このブログの使いまわしです)を披露してきました。印刷ネタを話す機会ってそんなにあるわけじゃないので予定時間大幅超過。ゴメンナサイ><。

喋りすぎたのはお許しいただくとして、わりかし好評でした(多分)。

他のみなさんの発表で面白かったのは、

  • DDTSS (Debian Distributed Translation Server Satellite) による Debian パッケージ翻訳。オイラも Printing まわりでなんかチャレンジしてみようかな。
  • ArduinoGainer 階段と ForCy-USB という電子工作三題話。それぞれに特徴があって面白いね。
  • USB-Net 変換ケーブルを用いた Printing の事例集。印刷ネタがオイラ以外から出るとは思ってなかったので思わずたくさん補足してしまった。
  • 有休PCを用いた Thin Client 環境の実例。X を生であげるのと、VNC を使うのとどっちがいいかという比較。
  • Solaris kernel + Ubuntu Skin という Storm OS という OS をみんなでトラブルシュートしよう。

ここにあげなかった活動報告も面白かったです。


懇親会ではいろいろなお話ができて楽しかった。
やっぱり勉強会やオフ会で一番大事なのは飲み会だね(^^)。

でもせっかくだから席替えして、話したことがない人ともっと話せばよかったかな、と反省。やや体調が悪かったせいか、そんなに飲んでいないのにちょっと酔いが回るのが早かったのもあるんだけどね。
Mizo さんに誘ってもらったし Solaris コミュニティも一度参加してみたいなぁ……。

まあともかくありがとうございました。
幹事のよしださんには大感謝!

Common Printing Dialog をデバッグしてみよう (その2)

d:id:naruoga:20090528:1243491493 のつづき。


ということで、Common Printing Dialog がバグってるということが分かったので、ではどこでバグってるかを探してみましょう。

その前に、今までコマンドラインから gdb を使ってきましたが、「ふつー emacsgdb モード使うだろ」ってことで今回から emacs にしてみ……たら、なんか上手く動かないので (猛烈に遅くて帰ってこない ><) 泣く泣くコマンドラインでやります。


さらにさらに、ぼんやりしてたら最新のレポジトリ (6/11 コミット) だと現象が変わってました。しくしく。なんの意図の変更なんだか bzr を使い慣れないのでよくわかりませんので、とりあえず古いバージョンでやってみますね。


まずは前回同様、kde4-dialog/kde4-cpd をバックグラウンドで起動しておいてから、gdb を起動します。

$ kde4-dialog/kde4-cpd &
$ gdb kde4-dialog/view-dialog
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run
Starting program: /home/naruhiko/common-printing-dialog/build/kde4-dialog/view-dialog 
[Thread debugging using libthread_db enabled]
[New Thread 0xb5f19940 (LWP 19299)]
ASSERT failure in QVector<T>::operator[]: "index out of range", file /usr/include/qt4/QtCore/qvector.h, line 335

Program received signal SIGABRT, Aborted.
[Switching to Thread 0xb5f19940 (LWP 19299)]
0xb800b422 in __kernel_vsyscall ()
(gdb) 

QtCore の QVector (まぁ名前のとおりベクタっていうかコンテナクラスなんでしょう) というクラスで [] オペレータの処理で転けてるということですね。

私はぶっちゃけ Qt は全然分からないのですが、さすがにこんなに基本的なクラスに虫がいるというのは考えにくい。当然、呼んでる側がバグってる可能性が高いということですね。
つーことで呼び出し関係を見るのに backtrace を見てみましょう。

(gdb) bt
#0  0xb800b422 in __kernel_vsyscall ()
#1  0xb66286d0 in raise () from /lib/tls/i686/cmov/libc.so.6
#2  0xb662a098 in abort () from /lib/tls/i686/cmov/libc.so.6
#3  0xb7658595 in qt_message_output () from /usr/lib/libQtCore.so.4
#4  0xb7658681 in qFatal () from /usr/lib/libQtCore.so.4
#5  0xb765872c in qt_assert_x () from /usr/lib/libQtCore.so.4
#6  0x08064941 in QVector<CommonPrinting::CUPSDestination>::operator[] (
    this=0xa0aef84, i=0) at /usr/include/qt4/QtCore/qvector.h:335
#7  0x0805dc40 in CPDialogWidget::initWidgets (this=0xa0aef50)
    at /home/naruhiko/common-printing-dialog/kde4-dialog/cpd_dialog_widget.cpp:861
...

ということで CPDialogWidget::initWidget() の中の QVector の呼び出しで転けていると。

もちょっと詳しく見るために、CPDialogWidget::initWidget() の先頭にブレークポイントをかけて逐次実行してみます。なんで直接 cpd_dialog_widget.cpp:861 を見ないかといういうと、さすがにロジックを追っていかないとバグの意味が分からないからです (^^;)。

(gdb) b CPDialogWidget::initWidgets()

Breakpoint 1 at 0x805db19: file /home/naruhiko/common-printing-dialog/kde4-dialog/cpd_dialog_widget.cpp, line 855.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/naruhiko/common-printing-dialog/build/kde4-dialog/view-dialog 
[Thread debugging using libthread_db enabled]
[New Thread 0xb5eac940 (LWP 19668)]
[Switching to Thread 0xb5eac940 (LWP 19668)]

Breakpoint 1, CPDialogWidget::initWidgets (this=0x892b120)
    at /home/naruhiko/common-printing-dialog/kde4-dialog/cpd_dialog_widget.cpp:855
855		presetLabel = new QLabel("Quick Presets:");
(gdb) n
859		        printerbox->insertItem(i + 1, printers[i].name());
(gdb) n
855		presetLabel = new QLabel("Quick Presets:");
(gdb) n
856		printerbox = new QComboBox;
(gdb) n
857		printers = CUPSSupport::getDests();
(gdb) n
858		for(int i = 0; i < printers.size(); i++) {
(gdb) n
861		currentPrinter = &(printers[0]);
(gdb) n
862		changerButton = new QPushButton("Control printing aspects");
(gdb) n
861		currentPrinter = &(printers[0]);
(gdb) n
ASSERT failure in QVector<T>::operator[]: "index out of range", file /usr/include/qt4/QtCore/qvector.h, line 335

Program received signal SIGABRT, Aborted.
0xb7f9e422 in __kernel_vsyscall ()

まずは b (breakpoint) コマンドで CPDialogWidget::initWidgets() の先頭にブレークポイントをかけます。ご存知のとおり b で関数名だけ指定するとその先頭にブレークポイントが設定されます*1

んで run すると「実行中のがあるけど再実行しちゃっていいの?」と聞かれるので y と答えて最初から実行。さっき設定したブレークポイントで止まります。
んで n (next) でステップオーバーしながらどこで死ぬかを見つけます。同じところを何回か実行してるように見えますが、これは最適化でシンボルと実際のコードにズレがあるからでしょう。

ということで死んでるのは先ほどのバックトレースのとおり 861 行目。printers[0] のアクセスで死んでいることが分かります。
ではこの printers とは? まぁ、わざわざ調べなくてもわかりそうなものですが、せっかくなのでもう一度復習。上のステップ実行のなかで、

857		printers = CUPSSupport::getDests();

ってのがあります。CUPSSupport クラスを調べるのはめんどうなので省略しますが、メソッド名から察するにプリントキューを列挙して printers にぶっこむという処理をするのでしょう。
試しにこの行を実行して printers の中を見てみると、

857		printers = CUPSSupport::getDests();
(gdb) n
858		for(int i = 0; i < printers.size(); i++) {
(gdb) print printers
$1 = {{p = 0x8070670, d = 0x8070670}}
(gdb) print printers.size()
$2 = 0

printers.size() は 0。つまりこのベクタ型は空っぽということです。そらそうですね、プリントキュー一個もないんだもん。

んでま、QVector のリファレンス を見ますと、

T & QVector::operator[] ( int i )

Returns the item at index position i as a modifiable reference.

i must be a valid index position in the vector (i.e., 0 <= i < size()).

とありますので、size() = 0 のときにこのオペレータ呼んじゃダメってことですね。


ということで非常に簡単な例ではありましたが、gdb を使ってバグの原因を突き止めることはできたと。満足満足。


ほんとはこのあと、「せっかくだからバグ直してみた」「Bugzilla に直した結果を投稿してみた」と続く予定だったんですが、今思いっきり修正中のようなので、それはまた別の機会に。
もっともこのバグ、printers.size() == 0 のときにアラート出して死ぬ以外に直しようないんですけどね。

*1:ところでクラス名 (CPDialogWidget) にはタブ補完が効くのだけど、メソッド名には効かないのはなぜかしら。