WhyRuby

2004-02-19 10:05:01 +0900 (1697d); rev 1

(Ruby を始めたころに書いた文章ですが、記念にとっておきます)

いったい Ruby のどこがいいのか? どのくらいいいのか? つーか本当にいいのか? まずはそのへんから。

なぜ Ruby か ――― 最重要事項

言語の好き嫌いは人によってさまざまだ。 最初に覚えた言語が一番いいっていう保守的…… いや悪かった、信念の強い人もいる。 あるいはスピードが速いのがいいっていう人もいるし、 'write only' にできるのがいいっていう人もいる。 さらには「新しいからいい」という節操のない…… じゃなくて、好奇心の強い人もいる。

が、しかし、しかしだ。Ruby がすごい理由はどれもあてはまらない。 Ruby が Ruby たる所以は「書くのが楽しい」ところなのである。 これはめちゃくちゃ重要なことだからもう一度書こう。

Ruby は書くのが楽しいプログラム言語なのだ!

どういうところが楽しいか

なにが楽しいってそりゃいろいろあるけれども、まずインタプリタだから、 サクっと書いてサクっと動かせる (そしてバグがみつかる)。

それから、組み込みのクラスライブラリがやたらに高機能。 String、Integer、Array、Hash、Regexp あたりがあれば たいていのものはできてしまう。 逆に、ときたま C なんか使ったりすると 「うわああっ、Regexp が欲しいよーーー」と叫んでしまうことも度々である。 しかも高機能とはいってもおしつけがましくないのがポイント。 「どーでもいいところ」だけがうまく覆いかくされていて、 その他の重要なところ、例えばアルゴリズムであるとか、 「ここで何をしたいのか」ということがストレートにだせる。

そして、文法に制限が少ない。たとえばこんなことも余裕でできる。

arg = if    a == 'a' then 'a'
      elsif b == 2   then 'b'
      else                'c'
      end

いちおう文末にはセミコロンが置けるけど あれは C / Perl ユーザのためのリハビリ用でしかないし、 Perl 由来で修飾の if unless もあるし、 メソッド呼びだしの括弧も省略できるし、 行の最後がカンマや二項演算子なら次の行に続くんだな、 と勝手に判断してくれる。これは次の例を見れば一目瞭然だろう。

obj.method_call arg1,
                arg2, arg3 if condition
str = 'a' +
      'b' +
      'c'

また「リテラルがそのままオブジェクト」というのもいい。 例えば、スクリプト中で 'a' と書くと もうそれがすでに String オブジェクトであり、 そのオブジェクトに対してメソッドを呼ぶことができる。

# str に 'string' を大文字にしたものを代入
str = 'string'.upcase

3 と書いたらそれは Integer オブジェクト (正確には Fixnum オブジェクト) である。

# 三回くりかえせ!
3.times do
  print 'ok'
end

こういう書きかたは始めはちょっとびびるけど、このような表現も Ruby の気持ちよさを加速している重要な要素だ。このへんは説明を 読んでいるだけではわかりづらく書いてみるとよくわかるという類の ものなので、ぜひ一度実際に自分で試してみてほしい。

美しいのだ

Ruby のソースコードは美し (く書けることがあるらし) い。 先に述べた「やりたいことがストレートに出せる」ということとも 関係あるのだが、とにかく余計なものがない。

また、動作に関してもそうだ。そのいい例がイテレータ。配列にアク セスするのに C みたいにいちいちサイズチェックをしながらやる必 要がなく、each 一発ですむ。

['a','b','string'].each do |i|
  print i
end

これを実行すると、'a' 'b' 'string' を 順番に i に代入して do...end が実行される。 つまり、ループの while 文とかループカウンタとかが each メソッドの中に隠蔽されているわけだ。 そのおかげでユーザはいちいちアクセスの仕方を知る必要がない。

ちなみに上の例は %w を使うともっときれいに書ける。

%w( a b string ).each do |i|
  print i
end

%w は文字列配列リテラルを記述するための専用記法だ。

ところで Perl にも each はあるけれど、それは組みこみ演算子で、 ユーザーが再定義することなぞ当然できない。 しかし Ruby では自分で好きなイテレータを定義することができる。

# ユーザレベル each
def each(array)
  i = 0
  while i < array.size
    yield array[i]
    i += 1
  end
end

# 自作の each を使ってみる
each([1, 2, 3]) do |i|
  print i
end

yield のところで制御がブロックの中に返ってくる。 「yield はブロックの呼びだし」と考えるとわかりやすいと思う。 高階の関数みたいなもんだな。

それから、モデルの面から言っても Ruby は美しい。 値は整数も含めて全てオブジェクトだし、クラスもオブジェクト、 コードもオブジェクトにでき、そしてオブジェクトでないデータは存在しない。

なんでもできる

Lisp ではプログラム自体がリストなので、実行時にプログラムを 変化させることができる。Ruby では「プログラムもオブジェクト」 というわけではないのだが、そのように扱うことはできる。 例えば前節でちょっと出てきた「ブロック」をオブジェクト化した Proc もこの用途に使えるし、eval や module_eval というメソッドを 使うことで文字列をコード化することができる。 こういうものを組み合わせると実行時にクラスにメソッドを加えたり、 クラスを作ったりできる。

class A
  def define_a
    self.class.module_eval(<<-End)
      def a
        print 'a is called'
      end
    End
  end
end

この define_a を呼ぶと、メソッド a が定義される。 この例そのままではなにもおもしろくないけれど、 実行時に文字列をいろいろいじってから module_eval してやればもっといろいろなことができる。

ついでに豆知識を一つ。 今、実行時にクラスを作ることを特別なことのように言ったけれども、 実はすべてのクラスは実行時に作られている。 つまり、class 文は「クラス定義」というよりも「クラス登録文」と言ったほうが近い。

遅いからイヤ?

Ruby はインタプリタ言語だから、 速度の心配をする人がいるかもしれない。 もちろん、例えば C で書いたプログラムと比べれば Ruby スクリプトは遅いにきまってる。 だが……それがなんだっていうんだ!

例えば C のプログラムより 50 倍遅くなったとして、 実行時間はどのくらい変わるだろうか。 もし C のプログラムが 0.01 秒で終わるとしたら、 Ruby 版は 0.5 秒。 あなたのプログラムは 0.49 秒速くするために C で書く価値があるか?

しかも、(インタプリタ全般に言えるけど) 大量の文字列処理や 入出力がからむと、差は小さくなる。 Ruby で書くのはそういうものが多いから、 さらにネイティブ言語にこだわる必要は小さい。

そして

プログラムは開発の時間よりも保守の時間のほうがかかるというのは もはや常識だけども、Ruby で書いてあれば例えば、 C で書いたプログラムよりも楽に保守できるはずだ。 そういう点でも Ruby は非常にいい。

だいたい、スピードに対してごちゃごちゃ言うなら C じゃなく アセンブラで書けばいい。それをなんで C で書いてるのかって言えば、 それはもちろん「コードがわかりやすい」とか、「早く書ける」って のが理由だろう。そして、Ruby は C よりわかりやすいし速く書ける。 ということは、「C よりも Ruby」というのは非常に自然な選択では ないだろうか?

CPU はじめハードはどんどん速くなってくれる。 いまはそれを某 OS とかが食いつぶしてくれたり、 某ワープロソフトがイルカを跳ねさせるために使ってくれたりするのだけど、 それはあまりに悲しい。 もっと、「カワイイ」とか、「カッコイイ」のために使うべきではないだろうか。 システム部分はサクッと Ruby で書いてしまえば、 我々人間はそういうコトに集中できる。

それにほら、そうすればしばらくイン×ルも CPU の性能を上げ続け る理由ができるでしょ? (^-^)


system revision 1.162