From: matz@... (Yukihiro Matsumoto) Date: 1997-05-09T16:52:30+09:00 Subject: [ruby-list:2922] chap 1 draft #2 まつもと ゆきひろです 草稿の第2版です. -- 1. rubyとは rubyは「プログラミングを楽しくする言語」です. プログラミングとは結局はコンピュータに行わせる仕事を厳密に記述する作業といえま す.この作業には楽しい部分と楽しくない部分があります.つまり,パズルにも通じる 知的な部分と,それ以外のこまごまとしたなかば機械的な作業です.機械的な作業の部 分は正直いって面白いとはいえません. コンピュータはあたまわるいので,私たちがやって欲しいと思ったことを推測して勝手 にやってくれたりしません.こちらがいちいち教えてやる必要があります.でも,単純 で機械的ななことならコンピュータでもわかることもあります.そういうことをコンピュー タが(プログラミング言語が)カバーしてくれれば,人間の高度な能力をより活かすこと ができるはずです.ですから,rubyは単純で機械的な作業をできるだけ省いて,プログ ラムを楽に書けるような機能を持っています.具体的にrubyにどんな機能があるかはこ の章の後の方で説明します. ちょっと大げさに表現すると,rubyの究極の目的は,有限の人生においてプログラミン グの楽しい部分にできるだけ集中できるように助けることです. rubyは「オブジェクト指向言語」です. オブジェクト指向については後の章で詳しく説明しますが,超簡単に説明すると『問題 を「オブジェクト」という存在とそのつながりで表現する』ことです. オブジェクト指向プログラミングでは,処理の基本がオブジェクトに必要な情報を与え て,『これをやれ』と命令することですから,現在注目している処理にとって重要でな いことは他のオブジェクトに任せることができるので,注目している問題の記述に専念 できます. それに,プログラムを構成する単位を「オブジェクト」とそれを分類する「クラス」と いう存在としてまとめることによって,機能をわかりやすく構成したり,プログラムを 再利用したりすることが比較的上手にできるようになります. rubyは「スクリプト言語」です. 「スクリプト」とは台本という意味で,簡単に作られ,場合によってはその場限りで捨 てられる小さめのプログラムを表します.スクリプト言語とはそのような「スクリプト」 の開発に向いた言語のことです.一般にスクリプト言語には * 短いプログラムで多くのことが行える豊富な組み込み機能 * 手軽にプログラムを記述し,すぐ実行できるインタプリタ という特徴があり,当然rubyもそのような機能を持っています. rubyは小さめのプログラムしか記述できないわけではありませんが,強力な組み込み機 能と高い再利用性によってプログラムが短めになる傾向はあるようです. == rubyの特徴 rubyは「楽しい」プログラミングを支援するため,以下のような特徴を持っています. * インタプリタ * 変数や式に型が無い * 変数宣言が不要 * シンプルな文法 * 全てがオブジェクト * 特異メソッド * モジュールによるMix-in * イテレータと手続きオブジェクト * 例外処理機能 * 強力な文字列操作/正規表現 * 強力な文字列操作/正規表現 * OSへの直接アクセスが可能 * メモリ管理が不要 * 多倍長整数を持つ * Cによる拡張が容易 * ダイナミックローディング * 組込みの安全チェック では,次節以降ではこれらの特徴をひとつひとつ見ていきましょう. === インタプリタ rubyはインタプリタ型の言語なので,コンパイルなどの手順無しにいきなりプログラム を実行できます.プログラムを修正してからすぐに実行できないと結構気分が悪く,待 ち時間はストレスになるものです.ストレスが溜ると精神状態が悪くなり,精神状態が 悪くなると良いアイディアも出て来るものではありません. rubyのようなインタプリタなら実行までの時間が非常に短く,いろんな意味で開発効率 が向上します.特に思い付いた修正をすぐに確認できるのは精神衛生上非常によろしい です.これが下手なコンパイラ型言語だとたった1行の修正でも,コンパイル・リンク して実行してみるまでに数分,あるいは場合によっては数時間かかる場合さえあります. もちろん,結果を早く出すことが至上である分野(たとえば数値計算など)や本当に大規 模なものでは開発効率よりも実行速度が非常に重要になります.インタプリタ型言語は 一般的にコンパイラ型の言語に比較して実行速度が遅いという欠点があるといわれてい ますので,そのような分野にはあまり向かないでしょう.しかし,マシンの速度は年々 向上していますし,そのような一部の分野を除いてはrubyのようなスクリプト言語で間 に合う時代はすぐそこまで来ているのではないでしょうか. 「「実際には ruby はプログラムを構文木と呼ばれる内部構造に変換して,それを解釈 しながら実行しますので,文法チェックなどは起動時に行われます.このような実行形 態をコンパイラ・インタプリタと呼ぶこともあります.」」 === 変数や式に型が無い rubyの変数や式には型がありません.プログラミング中に型の整合性について頭を悩ま すのはrubyの精神に反すると考えたからです.C++などのコンパイル時に決定される型 のある言語において,変数の型宣言や式の型変換が時としてわずらわしかったり,分か りにくくなったりすることをご存知の方も多いと思います.rubyではコンパイル時の型 チェックを行わない代わりに,実行時に手続き(メソッド)を呼び出せるかどうかでチェッ クしています. また式に型がないので,変数だけでなく配列なども任意の値を格納することができます. これはただの配列が柔軟に複雑なデータ構造も表現できることを意味します. % 配列に関して具体例があると良いんだけど…. 誤解されがちなのですが,rubyでは変数や式に型はないのですが,これはコンパイル時 には式や変数の型は分からないものの,実行時に値そのものが型を持っているのであっ て,全く型がないわけではありませんし,ある値がいつの間にか別のデータ型に変換さ れたりもしません.このような言語を『動的型付(dynamically typed)言語』と呼びま す.一方,同じように変数や式に型のない言語でも,awkやperlのような言語では,値 は使われ方によって文字列として扱われたり,数値として扱われたりします.このよう な言語は『型なし(typeless)言語』と呼ばれます.ちなみに変数や式に型のある言語は 『静的型付(statically typed)言語』と呼ばれます. === 変数宣言が不要 全ての変数は宣言無しにいきなり使うことができます.ただし,正確にはローカル変数 とクラス定数は代入が宣言の代わりになっているので,使う前に代入する必要がありま す. また,名前を見るだけでその変数や定数の種別(ローカル,グローバル,インスタンス, クラス定数)を区別することができます.たとえば foo ローカル変数(先頭が小文字) $foo グローバル変数(先頭が$) @foo インスタンス変数(先頭が@) Foo クラス定数(先頭が大文字) という感じです. 宣言が不要なことはそれほど重要なことではありません.プログラミングの観点からは ほんの少しタイプ量が少なくなる程度のメリットしかありません.重要なのは,宣言を 探さなくても,識別子を見るだけで,ある識別子がローカル変数であるか,グローバル 変数であるか,あるいは他のなにかであるかが明確にわかることです.例外として,引 数なしのメソッド呼び出しとローカル変数の参照は同じ形式をしていますが,これもそ の識別子に対する代入が行われているかどうかで判別できますから,そのメソッド定義 の範囲内で解決できます. このことにより,プログラミングの際にはひとつのメソッドに集中することができます し,情報が一箇所に集まっていますから,メンテナンスもしやすくなります. === シンプルな文法 スクリプト言語はいいかげんな文法の言語が多いのですが,rubyはシンプルながら,わ りとしっかりとした文法を持っています. === 全てがオブジェクト rubyははじめからオブジェクト指向言語として設計されていますので,整数などの基本 的なデータ型をはじめとして全ての値がオブジェクトであり,メッセージを送る統一的 なインタフェースを持ちます.ですから,値によって特別な扱いをする必要がなく,ユー ザが考慮する必要のある事柄がそれだけ少なくて済みます. rubyがオブジェクト指向言語であるメリットはそれだけではありません.オブジェクト 指向によって処理の「HOW(いかに処理するか)」よりも「WHAT(なにを解決するか)」に より集中できますし,既存のプログラムをクラスライブラリとして再利用できる可能性 も増えます. === 特異メソッド 他のオブジェクト指向言語にあまりみられない機能ですが,rubyではある特定のオブジェ クトにだけ有効な振舞い(メソッド)を定義することができます.同じ犬でも調教すれば 芸ができるようになるようなものでしょうか.このような特定のオブジェクトにだけ有 効なメソッドを特異メソッドと呼びます.この特異メソッドは,たとえばGUIで,ある ボタンを押された時の動作をそのボタンオブジェクトの特異メソッドとして記述するよ うな使い方ができますし,これを応用してプロトタイプベースのオブジェクトプログラ ミングも可能です(そんなことやる人はいないかもしれませんが). === モジュールによるMix-in rubyは意図的に多重継承を採用していません.多重継承はクラス間の関係を複雑にし, かえって理解しにくいものにするからです.とはいえ,単純継承だけでは,クラス階層 を横断して実装を共有することができません.rubyはこの問題を解決するためにモジュー ルを使ったMix-inという機能があります. モジュールというのはクラスと同じようにメソッドや定数を定義できる実体ですが,モ ジュールのオブジェクトを作ることはできません.モジュールで定義されたメソッドや 定数はクラスにincludeという機能を使って取り込むことによって利用できます.この モジュールの機能をクラスに取り込むことをMix-inと呼びます. === イテレータと手続きオブジェクト 手続きの抽象化を行うイテレータという機能があります.rubyのようなイテレータを持 つ言語は珍しいので,少し説明しにくいのですが,一連の手続きをメソッドに引き渡す ための仕掛けです.イテレータがもっとも良く使われるのはループの抽象化です.イテ レート(iterate)というのは繰り返すという意味で,ループの抽象化に使われることが イテレータの語源になっています. ループの抽象化とは,復数の要素をもつリストや配列などの各要素に対してなんらかの 処理を行いたい場合,リストや配列の内部構造に関係なく,ただ「各要素に対してこの 処理を行え」と指定して,アルゴリズムそのものの記述に専念できるようにすることで す.たとえば collection.each do |item| # itemに対する処理 ... end と記述するだけでcollectionが配列であるか,あるいは要素を格納できるなにか他のオ ブジェクトであるか全く気にせずに各要素に対する処理の内容に集中できます.このdo からendまでの範囲はイテレータブロックと呼ばれ,eachというメソッドの内部から間 接的に呼び出すことができます. rubyではイテレータは単なるループの抽象化だけではなく,手続きをメソッドに引き渡 す目的でいろいろに応用されます.たとえば,rubyの配列クラスには条件に合致する要 素を削除するdelete_ifというメソッドがあり,条件を指定するためにイテレータブロッ クを使います. array.delete_if do |item| # itemについての条件式 # 結果が真であれば要素が削除される ... end Cであれば関数ポインタを引き渡すような局面で,わざわざ関数を定義する代わりにイ テレータブロックを使うことができるわけです. このようにイテレータブロックを使えば手続きをメソッドに渡すことができるわけです が,rubyにはこの一連の手続きをオブジェクト化する機能もあります.このイテレータ ブロックをオブジェクト化したものを手続きオブジェクトと呼びます.手続きオブジェ クトに対してメッセージを送ることによってプログラムのどこからでも,もとのブロッ クを実行することができます. === 例外処理機能 rubyは配列の範囲を越えたアクセスやオブジェクトの型の違いなど,多くのチェックを 実行時に行っています.プログラム中の異常事態は例外という方法で報告されます.例 外が発生するとプログラムは呼び出し系列を遡って実行を中断しますので,毎回処理か 成功したか失敗したか確認する必要がありません. たとえば,例外がないと file = open(path, mode) if file == nil # 例外的状況への対応 # 例: エラーメッセージを出して終了 end と,いう風に処理が成功したかどうかチェックする必要があります.なんかいちいち 「できましたか?」と聞いているようであまり気分が良くないですよね.しかし,例外 があると file = open(path, mode) # 例外的な状況では自動的にプログラムが # エラーメッセージを出して終了 という風に毎回チェックすることは不要です.例外的状況の判定がなくなってプログラ ムがずいぶんすっきり書けます. しかし,処理が成功したか失敗したかいちいち調べないで済むのはありがたいのですが, 例外的な状況が発生した時に常にプログラムが終了してしまうのでは,時には困ること があります.たとえば,ファイルエディタで新規にオープンするファイル名を打ち間違 えたからといって毎回エラーで終了してしまったらちょっと悲しすぎます. そこでrubyの例外処理機能では必要に応じて例外を捕捉できます.簡単な例をあげます. begin file = open(path, mode) rescue file = open(path2, mode) end 上の例ではなんらかの理由でpathをopenできなかった時には,path2をopenすることに なります.このように指定しない時にもそれなりに,指定すればきめ細かに例外的状況 を取り扱えるのがrubyの例外処理機能です. === 強力な文字列操作/正規表現 一般的にスクリプト言語がもっとも良く使われるのはファイルなどから読み込んだ文字 列を加工する処理です.そのため,rubyは文字列を加工するための強力な機能を持って います.特に正規表現と呼ばれるパターンマッチの機能は,単なる一致検査の範囲を越 えていろいろ応用できる非常に強力な機能です.もっとも正規表現の機能を多用しすぎ るとスクリプトが暗号のようになってしまうという副作用があるのですが…. === OSへの直接アクセスが可能 rubyはUNIXのほとんどのシステムコールの呼び出し機能を持っています.その気になれ ばrubyだけでシステムプログラミングも可能です.UNIX版以外でもUNIXのシステムコー ルに類似したOSの機能を呼び出せます. === メモリ管理が不要 参照されなくなったオブジェクトはゴミになります.Cなどの低級な言語では使われな くなったオブジェクト(領域)はプログラマが明示的に開放してやる必要があります.し かし,この明示的な開放は面倒な上に,まだ必要な領域や割り当てられていない領域を 間違って開放してしまったり,逆に開放し忘れて領域が足りなくなったり,いろいろな 問題のもとです.rubyなら,もう参照されなくなったオブジェクトはゴミ集め(Garbage Collection, GCとも呼ぶ)という機能で自動的に回収されますから,プログラマはオブ ジェクトの開放について心配する必要はありません. このオブジェクトの開放の自動化は些細なようでも,メモリ関係のエラーは検出するの が大変むずかしいため,一度体験すると戻れないほどの快適さです.特にオブジェクト 指向プログラミングでは大量のオブジェクトを生成したり,それらが複雑に関係づけた られたりしますので,プログラマの負担の軽減は著しいものがあります. === 多倍長整数を持つ rubyには組込みの多倍長整数機能がありますので,非常に大きな整数の演算もできます. しかも,整数は演算結果の値の範囲に応じて通常の整数か多倍長整数に自動的に切り替 わりますので,たとえば,400の階乗などの非常に大きな値も普通に計算するだけで簡 単に求められます. def fact(n) if n == 1 then 1 else fact(n-1)*n end end print "fact(400) = ", fact(400), "\n" 多倍長整数はビット演算の場合にも有効で,rubyの全ての整数はビット演算の場合,仮 想的に無限の長さのビット列であるとみなすことができます.特に負の数の場合(2の補 数表現であると考えて),左側に無限に1が続いているとみなすことができます. printf "%x\n", 1<<3, "\n" printf "%x\n", 1<<300, "\n" printf "%.20x\n", -1<<30, "\n" printf "%.80x\n", -1<<30, "\n" === Cによる拡張が容易 C言語を使って比較的簡単にrubyに新しい機能を追加したり,既存のライブラリをruby から使えるようにしたりできます.rubyインタプリタ自身もコアになる部分以外は,そ の上に拡張用インタフェースを使って記述してあります.rubyの拡張用インタフェース は他のスクリプト言語の拡張用インタフェースと比較しても, * メモリ管理に関する記述がほとんど不要 * 特殊なマクロや構造体をあまり使わない * インタフェースが単純 であり,ずっと容易に拡張できると作者は信じています.rubyではネットワーク機能や データベースアクセスなどの機能が標準的な拡張機能として提供されています. この拡張機能によって,時間のかかる基本的な処理をCのようなコンパイラ型のシステ ムプログラミング言語で記述し,それをrubyで組み合わせて,柔軟で高速なアプリケー ションを作ることができます. === ダイナミックローディング 多くのOSでは実行時にrubyインタプリタに拡張機能を読み込む機能が提供されます.こ のダイナミックローディングの機能によって,インタプリタ全体を再リンクすることな しにrubyに機能を追加することができるので,拡張機能を追加するたびごとに再コンパ イルせずに済みますし,不必要な機能はリンクしないのでインタプリタの実行モジュー ルのサイズが小さくて済みます. === 組込みの安全チェック rubyには信頼できないデータによって不正な操作が行われることをチェックする機能が 組み込まれています.この機能は完全なセキュリティを保証するものではありませんが, 安全上の穴を検出しやすくする働きがあります.rubyの将来のバージョンではより完全 なセキュリティを提供する予定があります. == 簡単なプログラム ここまでrubyの特徴について説明して来ましたが,実際のrubyスクリプトの雰囲気を知っ てもらうためrubyの小さなプログラムをいくつか紹介しましょう. # 由緒正しい Hello world. print "Hello world\n" # 入力ファイルの"From "を含む行を印刷する while gets(); print if /^From / end # ファイルに行番号をつける while gets(); print $., ":", $_ end # πの計算 print 4*atan2(1,1), "\n" # 引数で指定したファイル名を小文字にそろえる ARGV.each do |path| File.rename(path, path.downcase) end % もうちょっと追加しないと…. == rubyに向いていること,いないこと もちろんrubyは万能の特効薬ではありません.向いていることといないことがあります. 正しく使って楽しくプログラミングしましょう. : 向いていること * 手早く作る小さなプログラム * フィルタ系プログラム * ファイル操作,文字列操作主体のプログラム * ruby本体または拡張機能で提供されている機能を組み合わせてできるプログラム : 向いていないこと * 速度が非常に問題になるプログラム * 数値計算主体のプログラム * 数万行にもなるプログラム == rubyのススメ 以下のような人にはrubyが向いているかもしれません. : 手軽にオブジェクト指向してみたい人 rubyは手軽にプログラムできるオブジェクト指向言語なので,とりあえず経験した いという目的にもぴったりです.また,rubyは既存のクラスライブラリを利用する スタイルのプログラミングも,自分でクラスライブラリを作っていくスタイルのプ ログラミングも両方サポートしています. : 入門用の言語を探している人 「『教育用にも使える』とあれば教育用にしか使えない」というマーフィーの法則 はrubyには当てはまりません.rubyのシンプルさと強力な機能は初心者からベテラ ンにまでぴったりです. : C++よりもましなオブジェクト指向言語を探している人 仕事でC++を使わざるをえない人はあきらめてください.でも,自分で使える言語 を選べる人にはrubyはお勧めです.もっともすでに述べたように中にはrubyにも向 かない分野があります. : 使いやすいオブジェクト指向ライブラリが欲しい人 rubyには豊富な機能を持つ使いやすいクラスライブラリが組み込まれています. : 思い付いたアイディアを手早く記述したい人 rubyはインタプリタなので書いたプログラムはすぐに実行できます.それにrubyの 強力な組み込み機能を使えば回りくどい記述をしなくても,やりたいことが手早く 記述できます. : 短気な人 プログラムが手早く記述できて,しかもコンパイルの待ち時間が存在しないrubyな ら,短気なあなたもあまりイライラしないですむかもしれません. : プログラミング言語が好きな人 rubyはプログラミング言語大好き人間が設計した言語です.言語好きのあなたなら, きっとrubyの良さがわかります. : 日本人 作者が日本人なので直接日本語で質問できます.rubyのことを扱ったメーリングリ ストでは日本語で活発な議論が行われています. : メモリ管理に苦しめられている人 rubyには使われなくなったオブジェクトを自動的に回収するGC機能がありますから, もうメモリ管理の苦痛から開放されます. あなたもrubyを使ってみませんか?