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

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

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

デザパタを一人でこっそり振り返ろう #1 (Iterator)

2011.02.27 注記:umejava さんのコメントにより、一部間違った記述を訂正。


最初は読書会に参加して勉強させて貰うつもりだったんですが、本来の趣旨であるところの:

GoF を基礎から丁寧に振り返りましょう

というテーマを無視してヨタ話に突っ走り、それはそれで非常に面白かったんだけど、むしろ基礎を押さえたい人を置いてけぼりにしてしまったことにいたく反省をして、読書会は抜けたわけで。

でも、そのためにせっかく買った

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

がもったいないやん! ということになり、抜けた読書会と同じペースで振り返ろうかな、とか思ってたらすっかりサボってしまいました。

そしたら注文してた、

Design Patterns Smalltalk Companion, The (Software Patterns Series)

Design Patterns Smalltalk Companion, The (Software Patterns Series)

が届いたので、眺めたら面白いのなんのって。


つーことで、以下さらさらっと舐めたいと思います。
以下結城先生の本は JDP、Smalltalk のヤツは DPSC と略記します。

Iterator パターン

d:id:naruoga:20110210:1297363662 で振り返った内容なわけですが、DPSC の見解は Ruby などの動的言語でも通用するんじゃないかな。

内部イテレータ

「ある固まり (Aggregator) に対して、その要素すべてにある処理を順に実行していく」という、その「要素すべてに」順次実行していく、という制御そのものを内部に隠蔽してしまうのが内部イテレータ

  • Smalltalk の場合 Collection クラスだったら内部イテレータを容易してるから、それ使えばおけ。具体的には do: で実行ブロックを渡すというありがちなやり方。
  • 逆に言えば Collection のサブクラスは do: を適切に実装しなきゃダメ。
  • イテレータ回してる最中に要素を削除したり追加したりすると悲しくなるので、そういうことしたいなら、あらかじめ copy メッセージ送ってコンテナをまるっとコピーしておけと*1
外部イテレータ

内部イテレータの方が記述がコンパクトだけど、処理を外部から制御したいときだってある。そういう場合は「進む」「戻る」という概念を外に出して、積極的に制御を外部に取り出してやる。これが外部イテレータ

  • Smalltalk の場合には Collection のサブクラスである Stream が外部イテレータとして使える。
    • ←2011.02.17 追記:Stream は内部イテレータである do: メッセージもサポートしていますが、クラス階層としては Collection のサブクラスにいるわけではありません。
    • non-Smalltalker 的には、Stream はファイルなんかの抽象概念ですよ、といえばいいのか。C# なんかにもあったっけ。
  • Smalltalk では String は Character の Stream なので、レキサとか書くのに便利だよ。
  • テキストエディタのアンドゥ・リドゥを実現したいときなんかにも Stream を使うといいよ。

ここまで丁寧に説明して貰うと、「内部イテレータだけでいくない?」という疑問がちょっと解消されるよね。


今 DPSC の Adaptor パターンを読み中なんだけど、こっちもすっげぇ面白い。早く追いつきたいよう。


でも今日はこれでおしまい!
ごめんなさい。

*1:空間効率いかにも悪そうだけど、オブジェクトを Copy On Write しとけば済む話なのかな。←2011.02.17 追記:Shallow Copyなのでそれほど重くないそうです。やっぱそうですよね。

デザインパターンと具象と抽象

昨日の話のちょっと続き。

抽象クラスの導出って難しい

私は元々、大学時代は人工知能の研究室にいました。
まあやってた内容は「人工無能との対話によって人間のもつ概念の曖昧さを具体化することができるか」という非常にウサンクサイ内容で、その対象としてソフトウェアの要求把握という題材を採って、知識表現としてのフレーム表現と、当時翻訳が出たランボーのOMTの本:

オブジェクト指向方法論OMT―モデル化と設計

オブジェクト指向方法論OMT―モデル化と設計

なんかを比べたりしてたんですけどね。

で、今の大抵のオブジェクト指向言語って継承概念があるじゃないですか。
でもね、人間って、ものすごく意識しないと、具象とか抽象とかってことを認識できないんですよ、私の感覚からいうと。

知識表現とかオブジェクト指向の例としてよく動物が挙げられますが(鳥は飛べる、鷲も鳩も鳥だから飛べる、けどペンギンは飛べないってのは「飛ぶ」メソッドを上書きして潰しちゃえ、とかね)、これは我々が学校教育で生物の勉強を多少なりともしているからです。だから生物の系統図的なものが頭に入っている。

しかし、そうでないものに対して、常に抽象化してものを考えられるかというと、それは非常に難しい。特にある「モノ」が一個しかない場合はなおさらです。上位下位概念と包含概念とか非常に混同しやすいですしね。
例えばプログラミングの初学者が配列「だけ」を見て、いわゆる「コンテナ」というものの一つであるということを思いつくことは、たぶんムリです。

だから「実世界を、今考えている応用の視点でモデル化して、それをクラスに抽出する」というやり方だと、往々にしてオブジェクト指向のお題目である「クラスの再利用により生産性が上がる」というのがうまくいかないという問題意識があったんではないかなと。

ということで、デザインパターンというのは、「じゃあよくある抽象化を公式としてパターン化しちゃおうよそうだそうだ」ってことなんじゃないかと想像しているのです。よく訓練された人でないと非常に難しい抽象クラスの導入を公式化してやるってことがミソなんではないかと。

そーゆー意味で、オブジェクト指向=継承、という考えをほぐすために、抽象データ型とか、あとJavaScriptみたいなプロトタイプ型オブジェクト指向(親とか子とかいいから、似てる奴からパクッちゃえ)なんかをやっとくといい気がするなぁ。

そして再び継続の話

しつこくてすみませんが、結局「継続」のような概念についても同じなんじゃないかと私は思うんです。
これは言語感覚の話なので、あくまでも私の「感覚」ということでお考えください。

昨日のついったの議論でもあったように、「継続 (continuation)」とは「ある一貫した処理の、途中までやったその続き」というのが一般的な定義です、よね。まぁ Wikipedia の説明でも読んでみてください。昨日ちょっと話に出た、Cのsetjmp()のこともちょっと書いてありますね。例外処理も継続の一種だなんてのは興味深いと思います。

では継続という概念を導入して何が嬉しいか。
それは、「実行状態を保存して続きをやる」ということに名前がつくことがまず一つ。
でもぼくは、それはうれしさも中位なりだと思うんですな。
「ああそれは継続を使うんだね」といったとき、実行状態を「どう」保存するかは各自考えなさい、じゃ、言われたってぜんぜん嬉しくないでしょう? 論文書く人はうれしいかもしれないけどさ。

だから「どう」保存するかも抽象化した、最低でも「パターン」が欲しい。そこまでして、「継続を導入する」とか、そういう用法に重みが出てくると思うんです。だって、それならそのパターンを使うってことで、やることが明確になるから。

そしてどのようなプロセスであっても抽象的に「ここまでやった、残りはあとで」ってことをしたければ、「実装としては」実行コンテクストを保存するしかないじゃないですか。だって、どんな処理かわかんないんだから。そしてそれは多くの言語で実現がとても困難、というのは先に述べたとおり。

ただし、「どんな処理でも、っていうのはムリだけど、こんな処理に限定して、っていうことなら、こういうクラス/関数/なんとかかんとか、を書けば、ある程度抽象化できるよ」ってのはあるでしょうね。それを綺麗にパターン化できるなら、意味があるかなと思う。ただし私は頭のいい方ではないので、これについては具体例が思いつかない。

あんままとまってないけどまとめると、

  • 定義として「継続ってのはある処理のある時点からの続き」ってのはある。
  • けどそれを「実装する文脈で」使ってもうれしくもなんともない。
  • 実装する文脈でうれしいというには、抽象概念に対応した具体的な何かが必要。
    • 「具体的な何か」として実装ということなら、実行コンテクストを保存するよりないし、それは多くの言語で困難。
    • 「具体的な何か」として、汎用性をある程度捨ててもよければデザインパターン的なもので対応できるかもだけど例は思いつきませんゴメンナサイ。

つまり、なんですな、「なんのために」「なにを」抽象化するかってこと。
結局具象化したものを綺麗に便利に使いたいから抽象化するんでしょうと。

コード書くのではなくて、論文を書くんであれば別でしょうけど……デザインパターンってコード書くための生活の知恵なので、その勉強をするというコンテクストであれば、「継続」も生活の知恵になってくれなきゃ概念を導入する意味がない、というふうに、私は感じています。

デザインパターン読書会 #1

@cesare さん主催のイベント。

増補改訂版Java言語で学ぶデザインパターン入門

増補改訂版Java言語で学ぶデザインパターン入門

を読んだ結果、思ったことなどなどを持ち寄りつつ、いろいろ議論をしようという会です。
趣旨は少なくともそうだったはず。

ごめんなさい、なんだかディープな雑談ばかりになってしまった。
もっとベーシックな方向で話をしたかったですね。

Iterator パターン

今回は第1章でIteratorパターン。

最初から、Iterator パターンは while ループが外に出たままで、抽象化が不完全、という話が出た。いわゆる、外部イテレータと内部イテレータの話ですね。
Smalltalk だったら例えば*1

#(1 2 3) do: [:n | Transcript cr; show: n] 

というふうに、do: に処理をブロックで渡して、Array 側で処理してもらえるわけで、こういうほうがいくね? っていう。

まあ、私も外部イテレータは気持ち悪いと思うんだ。けど、メソッドそれ自体を引数に渡すって手段がないJavaという言語なら、しょうがないかなあって感じる。でもなぁ、C++なら関数ポインタでイケる気がするんだけど。
ともかく、「データ構造が違っても同じように使える」は、十分嬉しい抽象化だと思うので、それはそれでいいと私は思う。

私としては一番のふむふむポイントは、AggregatorとIteratorを分離することで、Iteratorをnewするごとに「最初から値を取り出す」って処理をどんどこ行うことができるってことかなと。

あとスレッドセーフの話が出ましたね。イテレーションしてる間に外部からデータ書き換えられちゃったらどうするんだと。まあ、それについては応用編なので、結城先生の別の本を読みましょうってことで。

大事なのはデータ構造がどうなってても、hasNext と next という統一したインターフェースで処理が記述できるってことなんだよって話になって、配列とか線形リストとか木構造とか、あるいはファイルシステムだとかデータベースだとかそういうことをぜーんぶ無視して同じように扱えるってことだよねって話をした。

ここで「木構造でnextを実現するには継続が必要じゃない?」という発言が出て、えっ、って感じで、いやいやそんなことないでしょう、次を返すのに必要な情報さえあれば十分なんだから、継続とか持ち出さなくても大丈夫でしょう、という話をしたんだけど、これが後でモメるネタになるとは。


あとGoFだとfirst/get/nextという構造なのに、結城先生の本だとhasNext/nextという作りなのはなんでだろ、という話になったけど、これは多分、GoFだとC++だから

for (it.first() ; !(it.isDone()) ; it.next()) {
   val = it.get()
}

と、for文が綺麗に書けるからってことかなぁって話になったような気がする。
じゃあなんでJavaではそうしなかったの? というと、while一個で簡潔に書きたかったからなのかなぁ。
例えば first() も next() も要素が返せなかったら null を返すようにして、

book = it.first()
while (book != null) {
    System.out.println(book.getName());
    book = it.next()
}

みたいな書き方 (それどこの LotusScript? という声が聞こえた) もできるだろうけど、イディオムとして冗長だし、返却値で動き分けるのって綺麗じゃないよね、C じゃないんだから。だから、妥協点として正しい気がしてきた。

話戻って外部イテレータ対内部イテレータ

外部イテレータってイケてないよねなコト。
無論?私もそう思うんだけど、なんでそうなのかな、と帰る道々考えた結果、次のような屁理屈をあみ出した。

外部イテレータと内部イテレータの大きな違いは「制御構造を隠蔽しているか、外に出ているか」なんだけども、それによって生じる内部イテレータの大きな利点の一つは、制御構造を隠蔽することによって、データ構造に最適なイテレーション (例えば再帰とか) が容易に選択可能なことなんじゃないか、と。

でも本質論からいうと、それって言語の持つ再帰という機能によってスタックフレームに状態の保持を押し込めているだけで、状態を保持しなければイテレーションはできないんだから、それをどうやるかという手段の話でしかない、とも、私は思うのです。

いや、実装する人間としては、きれいに書けることは嬉しいが :)

継続についてあれこれ

そこでついったで一モメした*2 継続について。


えーと、ああいう文脈で「継続」といわれると、もちろん SchemeRubySmalltalk が言語機構として持っている継続が浮かびますね。
でも先程の再帰の話と同じく、言語として用意されているかどうかは本質じゃなくて、「継続」という概念ってのは何の抽象化なのか、ってのが大事だと思う。

イテレータの例でいうと、配列のイテレーションならindexを内部状態として保持しておけば、next() は作れる。簡単ですね。
でも木構造の場合、スタックに分岐点のノードオブジェクトの参照をプッシュしていって、葉までいったらそれを返すとともに、スタックから分岐点を取り出して次の枝に降りていく、ということをやらなきゃいけない。めんどくさいですね。めんどくさいけど、データ構造に見合った処理をしてるだけです。つまりぜんぜん抽象化していない。めちゃんこ具象です。

そして私は「継続」という「概念」を、上の二つの例を、その具体的な処理内容に依らず、途中で止めて、任意のタイミングで再実行できるしくみを用意することだと自分の中で定義しているわけです。これは、前記の言語が提供している機能がそうなので、言語設計者が抽象化したかった概念がそうだと解釈しています。
もちろん、それは言語にビルトインされていてもいいし、自前で頑張って書いてもいいけど、イテレータがそのイテレートする対象のデータ構造を隠蔽しているが如く、継続においては継続の対象となる処理を隠蔽していなければならない。これは必須だと考えています。
それを実現するためには、実行コンテクストを保持しておくって実装をエイヤコラと書かねばならん。とっても大変だと思うんですが。というか、普通の言語だとそこまで言語自身で制御できないのが多いんじゃないかな。
Z80で実装できるって話が出てたけど、むしろZ80ならできるでしょう。Cでもできるかもしれない……んーインラインアセンブラの力を借りないと難しいか? 普通の言語だと実行コンテキストなんてものは隠蔽されてしまっているから触れないから、非常に難しいと思うなぁ。
あ、Smalltalk ならコンパイルされたバイトコードを手で触れるので、こういう実装は得意……だそうです。受け売り ;-P

つことで、ぼくが「概念」として持っている「継続」は言語の上で実現するのは非常に難易度が高く感じるので、そこまで大げさな話じゃないでしょう? というのが、「木構造イテレーションだって継続なんか要らない」という主張なんです。


もちろん、「止めてたものを再開できる仕組みなら全部継続」という立場もあるでしょう。でもそうしたら、配列のindexを内部状態として保持する、という実装を「継続」と呼ばない理由がない。「木構造には継続が必要」なんではなくて「イテレートにはすべて継続が必要」ということになります。当たり前すぎますね。
それが正しいのであれば……そんな当たり前なものに名前つけて「概念」だなんていうのは大仰というかもったいないなぁ、というのが私の率直な感想。


という話を140文字で表現しようとした私が悪かったです。猛省しております……。

おわりに

参加して議論に加わってくれた皆さんありがとうございます。
ぼくは Java はぜんぜんわかんないんで、色々勉強になりました。
ただ時間に余裕があるなーと思うと脱線してしまう傾向があるので、2章ぐらいずつやってもいいかなとぼくは思いました。

それとついったでギスギスした雰囲気にしちゃったことは本当に反省しています。
これに懲りず、次回も楽しく議論できればな(できれば脱線方向ではなく、基本に立ち返る方向で ^^;) と思います。

*1:せめて Ruby で書けって? まあ、そういうことは言わない。

*2:私としては、議論を投げたというか、私には上手い説明ができませんゴメンナサイ、という白旗を揚げたつもりだったんだけど、ああ返されちゃうとちょっと平静ではいられないわけでして。お子様ですみません。反省しております。

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

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

あたしゃ一介のプログラミング言語好きなので (マニアの域には全然達していません。変態的趣味ではあるけど) まじめに答えは期待してないと思いますが不真面目に答えます。
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 コミュニティも一度参加してみたいなぁ……。

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