2009-10-15

"初めてのRuby" Yugui 著

タイトル通りRuby入門書である。ただ、オブジェクト指向を少しぐらいかじっていないと読むのも辛かろう。前記事の「プログラミング言語 Ruby」と重複するところも多いが、よりコンパクトで、具体例はこちらの方が多い。頭の鈍い酔っ払いには、二冊セットで読むとちょうどよい。本書は、リファレンスを読むための手引書のような位置付けにある。ちなみに、著者のYuguiさんとは、園田祐貴さんのことでRuby1.9系統のリリースマネージャと紹介される。自らMtF-TS(Male to Female Transsexual)と告白されるように、その勇気には頭が下がる。こういう方にこそ研ぎ澄まされた感性や才能が宿りやすいのかもしれない。

人間は物事を考える時、自分で使いこなせる言語で思考するところがある。ただ、精神は言語を飛び越えた領域で思考するところもあって、言語学者は対象言語の外側から物事を眺めているのだろう。ちなみに、アル中ハイマーの精神は、しばしば自らのボキャブラリ障壁を越えられなくてイライラする。日常使われる言語には、民族の持つ文化や慣習といったものまで背負い込む。プログラムを書く時も同様に、プログラマは自然とプログラミング言語に沿って思考するところがある。そして、プログラミング言語の持つ文化や慣習といったものが思考の中に入り込む。したがって、システム構築にはプログラミング言語の選択も重要となろう。
ポール・グレアム氏は、著書「ハッカーと画家」の中で、「ハッカーというのは、言論の自由に対してものすごく執着するものなんだ。」と語った。仕事の要求が高ければ、より優れた言語を使うことで効率を上げたいと考えるだろう。だが、実際にはそれほど要求の高くない仕事がゴロゴロしている。よって、慣れ親しんだ言語を使ったり、流行を追いかけるのも悪い選択ではないだろう。言語は過去の資産や組織の政治力によって強要されることもあれば、言語には宗教のようなところがあって洗脳されるケースもあって、純粋に言語選択といっても難しいものがある。多くの言語に触れなければ的確な選択判断が難しいと同時に、一つの言語を深く使いこなさないと本質を理解できないというジレンマがある。したがって、酔っ払いには噂に流されることぐらいしかできない。
Rubyは、純度の高いオブジェクト指向言語として名高い。また、SmalltalkやLispの影響を受けた言語で、複雑なシステムを最小コストで構築する能力があると言われる。Rubyの古い謳い文句に「驚き最小の法則」というものがあるという。なるほど、その思想はシンプルである。数値や文字列、正規表現、入出力などすべてがオブジェクトで構成され、すべてのオブジェクトはメソッドを通して統一的に操作できる。
歴史的には、「より良いPerl」として受け入れられたそうな。Perlといえば、その自由さによって暗号文っぽくなりがちで、自分で書いたコードですら後で見るのが嫌になる。そんな酔っ払いが、Rubyを使えばスパゲッティコードから解放されるとは言い切れないだろうが。
また、「動く擬似コード」と評されることもあるらしい。ほとんどのプログラミング言語は、コンパイルのためのおまじないといった余分なコードが含まれる。その点、Rubyは本質的なコードのみを書くので解読しやすいという。そういえば、最近、数学書やアルゴリズム解説書で、Rubyで書かれたサンプルコードが付録されるのをよく見かける。これも、余計なおまじないがなく要所を押さえたコードということだろうか。
本書は、Rubyらしく考えることを主眼に置いている。言語を理解する上で、単なる文法法則だけを紹介されてもつまらない。言語の流儀や文化を知ることに意義がある。

ところで、オブジェクトとは何か?なんとなく目的を持って振舞う塊のようなもの。そして、多くの塊が協調しながら一つのシステムを形成する。こうした構造は、人間精神のメタファを感じる。精神には、一つの目的を持った意識のようなものが形成され、人間は多くの目的意識を見出しながら生きている。では、それぞれの意識は、何によって制御されたり操作されたりするのだろうか?そこには意志というメッセージが飛び込んでくる。これがメソッドだ。意志とは、石のような頑固な塊であって、それぞれが協調しながら妥協の中で目的を果たそうとする。その目的を持った意志が失われた時、精神は死んだり、精神病を患ったりする。目的を持った意志とは、欲望と解釈することができる。オブジェクトがデータ構造の管理を怠れば、メモリリークも起こす。そして、精神もパニックを起こし、犯罪を犯すことだってある。それが衝動ってやつか?こうした致命的なバグを言語仕様によって防ぐことができればありがたい。では、精神の衝動を抑える合理的な手立てはあるのだろうか?それが理性ってやつか?プログラミング言語の思想にも、危険な操作をすべてプログラマの良識に任せるか、すべて抑制するかという論争がある。ちなみに、Rubyの文化は前者のようだ。これも大人の世界ということだろうか。したがって、オブジェクトの構築には理性構築に通ずるものを感じる、のは気のせいか?

1. バージョン体系
MRI(Matz' Ruby Implementation)のバージョン体系は、"MAJOR.MINOR.TEENY"となっていて、MINORが偶数のバージョンが安定版で、奇数が開発版なのだそうな。ただし、1.9系統は変則で、TEENYが1以上のものが安定版で、0が開発版なのだそうだ。また、1.9系統は2.0系統の踏み台を意図しているという。なんとなく2.0に期待するのであった。

2. データ構造
Rubyは、だいたいにおいて定義が緩やかである。しかし、型変換では厳密な面を見せる。Perlのように、外部からの値を必要に応じて数値や文字列と勝手に判断して型変換をする言語は、あまり好まないのだが、Rubyの型定義の緩やかさの按配は酔っ払いの肌に合う。Rubyは、to_i, to_f, to_sなどの型変換メソッドを用意している。ちなみに、定数も変数でありオブジェクトである。ただし、定数を変更すると警告を発してくれる。
「Rubyは、すべてがオブジェクト構造をとるため、オブジェクトへの参照を別のオブジェクトへの参照へと対応付けるデータ構造をとる。」
といった表現がやたらとちりばめられる。なるほど、変数への代入は正確にはオブジェクトへの参照を代入していることになる。これは注目すべき性質であろう。例えば、以下のように動作する。
------------------
cattle = "yahoo"
animalx = cattle
animaly = cattle.dup # 複製メソッドで明示すれば分かりやすい
cattle[2] = ?p
p cattle # "yapoo"と表示
p animalx # "yapoo"と表示
p animaly # "yahoo"と表示
------------------
酔っ払いは、いかにもオブジェクト指向らしいこの性質に惹かれる。というのも、イテレータで書くと何をやっているかを明示できて、文章っぽくなるのがいい。
ところで、配列などでデータの範囲外にアクセスすると、他の言語では例外を起こすだろう。Rubyは、概して範囲外添字に対して寛容で、nilを返すだけである。この思想が良いか悪いかは、好みの分かれるところだろう。ちなみに、厳格に例外を発生させるfetchメソッドも用意されてる。
オブジェクトの占有するメモリは処理系が管理して解放するので、プログラマが管理に悩まされることはないという。ガベージコレクションが自動でメモリを解放するからである。だからといって、メモリリークが絶対に起こらないというわけでもないだろう。やたらと寿命の長い参照を作るコードが危険であるのは同じである。

3. 数値演算
多倍長整数をサポートしているので、桁あふれを心配せずに大きな数を扱うことができるという。Rubyの数値計算が遅いところは、少々気になるところである。それも1.9では大幅に改善されているそうな。言語によっては、32bitや64bit長という制限があるが、Rubyの整数型には制限がない。整数オブジェクトは、IntegerのサブクラスであるFixnumクラスとBignumクラスで実装される。Fixnumは固定長で実装される整数で、Bignumは多倍長で実装される整数で、これらのクラスを自動的に使い分ける。言うまでもなくFloatオブジェクトの実装はIEEE754に従っていて、その精度はシステムに依存する。IntegerクラスとFloatクラスの親クラスはNumericクラスである。
ちなみに、左辺が右辺よりも小さければ負の数を、等しければゼロを、大きければ正の数を返す比較演算子 <=> を、宇宙船演算子と呼ぶらしい。おいらには宇宙船の形には見えないが。
他に、数値演算に欠かせない複素数クラスや有理数クラスが提供されるのはありがたい。

4. 文字列
この手の言語で、正規表現などのunix流のテキスト処理は必須であろう。Rubyは、PerlやAwkといったシェルスクリプトを受け継ぐ。また、文字列操作のメソッドやイテレータが豊富なのも特徴である。1.9では、マルチバイト文字に対応した多言語テキスト処理をサポートする。マジックコメントは、emacsやvimにファイルのエンコーディングを知らせる方法を流用している。
Rubyには、文字クラスなるものが存在せず、マルチバイトのエンコーディングも含めて、すべてStringクラスで対応している。Rubyのライブラリ設計には、「大クラス主義」というものがあるらしい。むやみにクラスを増やしたり余計な階層化をしないという思想である。
正規表現は、1.8ではGNU regexを改造した独自のエンジンを利用していたが、1.9では「鬼車」というライブラリを採用して機能を強化しているという。
ところで、文字列とは別にシンボル(Symbol)という似通った概念がある。シンボルの特徴は、その唯一性と軽量性にあるという。文字列同士は内容が同じでも同一のオブジェクトとは限らない。対して、シンボルは内容が同値であれば同一のオブジェクトになるという。へー!オブジェクトが同一であるかを調べる場合、文字列よりもシンボルの方が高速に動作するという。シンボルは内容に対する唯一性を維持するので、文字列とは異なり変更不能(immutable)となる。このような性質はハッシュのキーなどに適していそうだ。

5. 入出力
しばしば、Rubyのクラスはunix文化に基づいていて、posixやシステムコールやC言語ライブラリ関数をオブジェクト指向でラップした形になっているという。IOクラスもその典型と言えよう。ファイルをオープンすると、ブロック付きメソッドによって自動的に閉じてくれる。こうしたライブラリがリソースを管理してくれるのはRubyの利点の一つである。リソースを手動で管理することもできるが、その時はcloseメソッドが必須となる。標準入出力やFILEやARGF以外にもIOオブジェクトがある。StringIOは、文字列に対してIOオブジェクトであるかのように振舞うラッパークラスである。1.9では、入出力も文字列と同様にエンコーディングを扱うことができるらしい。

6. 変数と式
Rubyの慣習で、変数名にcamelCaseやPascalStyleのような、大文字小文字で単語を区切るべきではなく、pascal_styleのようにアンダースコアで区切るべきだという。尚、クラス名のみは例外で、PascalStyleといった大文字小文字で名前を付けるらしい。
そういえば、Rubyには、インクリメント、デクリメント演算子がない。導入するかどうかという議論もあるらしいが、強力なイテレータがあるので不便を感じないということらしい。例えば、以下のようにやればいい。
0.upto(9){|i| puts i}
str = "Diogenes"; str.each_byte{|byte| puts byte}
多重代入で、a, b = b, a とやれば、値が交換できるのは便利。論理演算子は短絡評価にも使える。a || b は、aの値が真ならば、bの値を評価せずにaを返す。aの値が偽ならば、bの値を評価する。同様に、a && b は、aの値が偽ならば、bの値を評価しない。
ifやwhileなどの制御文は、Rubyでは値を返す式なので制御式と呼ぶそうな。ちなみに、ループ系の制御式は、loop, times, uptoなどのイテレータを使うとコンパクトに書ける。

7. メソッド
あらゆるオブジェクトにselfが存在する。C++やJavaのthisのようなものである。デフォルトのレシーバがselfなので、クラス内では省略できる。配列では、sortやuniqなどのメソッドが提供される。uniqは重複する要素を排除するメソッドで、元の配列を破壊しない新たな配列を生成する。対して、uniq!は破壊的メソッドとなり、元の配列から重複要素を削除する。一般的に破壊的メソッドは、末尾に!を付ける慣習があるようだ。
非オブジェクト指向的なメソッドに関数メソッドがある。厳密に言えば、どこかのオブジェクトに属するので、Rubyには純粋な意味での関数は存在しないようだ。つまり、トップレベルのメソッドである。
値を返す時は、returnを用いることができるが、省略すれば、メソッドの末尾の式の値が返される。ただし、多値を返すにはreturnが必須。ちなみに、void関数のような値を返さないメソッドは存在しない。神経質なプログラマは、意味のない値を返すよりも、意図されないようにnilを返すように書くらしい。
メソッドによっては、ブロック付きで動作させたい場合がある。ブロック付きメソッドを定義する時は、yieldを利用する。

8. クラスとモジュール
クラス名は大文字で始まる識別子でなければならないという。これはクラス名が定数名でもあるからだそうな。クラス定義の変更を禁止したい時は、freezeメソッドを使用すればいい。ちなみに、組み込みクラスを含む重要なクラスでも、初期状態ではfreezeされていないという。プログラマの良識に委ねているということか。
モジュールはクラスと似ているが、「インスタンス化できないクラス」のようなものだという。ClassはModuleのサブクラスである。モジュールの特徴はMix-inと名前空間にあるという。Mix-inは、制限された多重継承で、そのイメージはトッピングのような意味あいだろうか。ArrayやHashクラスには、EnumerableモジュールがMix-inされるので、その関係のイテレータが自由に利用できる。クラスにComparableモジュールをMix-inすれば、比較機能を自由に利用できる。

9. その他
gdb風のデバッガが標準に装備される。
$ ruby -rdebug hello.rb
pという信じられない短いメソッドがある。これはデバッグに用いられるメソッドでirbと共に重宝されるが、デバッグや学習、コードゴルフ以外に用いるのは行儀が悪いという。おいらは、このメソッドに病み付きだ。
RubyGemsはパッケージ管理システムで、インストール可能なパッケージの一覧などを参照できる。RubyGemsには、Ruby/GD2などの画像ライブラリやネットワークライブラリもある。
wxrubyは、クラスプラットフォームなGUIツールキットwxWidgetsをRubyから利用するためのライブラリである。

0 コメント:

コメントを投稿