私はこれで Perl から乗り換えました。

副題
Ruby ホームページの言
『Perlのような手軽さで「楽しく」オブジェクト指向しようという言語です.』
これは正に真なり!

Perl はとても強力な言語です。これで書けない処理というのは、ほとんど 無いでしょう。その強力さにひかれて、Programming Perl の日本語版が出版 された頃からずっと使い続け、一生?使い続けるだろうと思っていました。

しかし、昨年(1997)末に Ruby を試してみたところ、その素晴らしさにあっ さりと乗り換えてしまったのです!

あれほど強力な言語から簡単に乗り換えさせてしまうとは、なんと凄い言 語でしょう。Perl ユーザーでない方にはちょっとわかりにくくなるかもしれ ませんが、その素晴らしさを Perl と比較して紹介します。

[INDEX] [Ruby HOME]

1. 基本的な書き方

まず最初の大きな違い。Perl は後からオブジェクト指向を採り入れた為、 記述が少し冗長になってしまっています。

package Test_class;
sub new {
        bless my $self = {}, shift;
        $self;
}
sub test_method {
        my $self = shift;
        # code
        $self;
}

クラスの初期化時の処理が特に無くても new メソッドの記述が必要。各メ ソッドの定義の最初には、オブジェクトを示す値を保持し、最後にはその値を 返さなければなりません。(絶対に返さなければならないというわけではあり ませんが、多くの場合はこうなります。)

これに対し、Ruby は最初からオブジェクト指向である為、すっきりとした 記述になっています。

class Test_class
  def test_method
    # code
  end
end

クラスの初期化時に何か処理が必要な場合は initialize メソッドを利用 するようになっており、必要なければ省略出来ます。メソッドの記述は、オブ ジェクトとしての値を保持するのは当然なので、それに関する記述はありませ ん。

とてもすっきりと書けて良さそうですね。しかし、数行の記述を省略出来 るというだけの事なので、それを気にしなければ乗り換えるほどの魅力にはな らないでしょう。

2. 値の受渡し

次に、メソッドの値の受け取り方をみてみます。まず、Perl では次のよう になります。

sub test_method {
        $self = shift;

        my ($foo, $array, $hash) = @_;

        print "foo   : ", $foo,    "\n";
        print "array : ", @$array, "\n";
        print "hash  : ", %$hash,  "\n";

        $self;
}

受け渡す時には、test_method($foo, \@array, \%hash) のように、リファ レンス(それらを示すポインタ)を渡します。そして、受け取った後では、 @$array, %$hash のようにして戻してやらなければなりません。

これは、配列もハッシュも単なる値の集まり(極端に言えば、どちらも単な るリストでしかない)であるため、そのまま渡すとそれぞれの境界が判断でき ず、ダーっと展開されてしまう事を回避する為に取られた手段です。

一方、Ruby では次のようになります。

def test_method(foo, array, hash)
  print "foo   : ", foo,   "\n"
  print "array : ", array, "\n"
  print "hash  : ", hash,  "\n"
end

これもまたすっきりしますね。まず、変数もオブジェクトであり、自分の 持つデータの型を保持しています(正確には、データの型を保持しているので はなく、それに従ったクラスに所属するようになるのですが)。そのため、 Perl のように $@% 等を付けてデータの型を知らせてやる必要がありません。

そして、有効範囲別に変数名が決められている為(ローカル変数は英小文字 で始まり、グローバル変数は $ で始まる)、それに従って命名するだけで、 Perl のように一々(my 等で)ローカルに有効範囲を制限したりする必要があり ません。

ややこしくなりやすいポインタ渡しが必要無いというのは、ちょっと魅力 でしょう。

3. 引数のデフォルト値

次に、引数が渡されなかった場合のデフォルト値の処理をみてみます。ま ず、Perl ではこのようになるでしょうか。

sub test_method {
        my $self = shift;

        my ($foo, $array, $hash) = @_;

        $foo    = 1                unless $foo;
        @$array = (1,2,3)          unless $array;
        %$hash  = ("a"=>1, "b"=>2) unless $hash;

        print "foo   : ", $foo,    "\n";
        print "array : ", @$array, "\n";
        print "hash  : ", %$hash,  "\n";

        $self;
}

だいぶ長くなってきましたね。Ruby ではどうでしょう。

def test_method(foo = 1, array = [1,2,3], hash = {"a"=>1, "b"=>
2})
  print "foo   : ", foo,   "\n"
  print "array : ", array, "\n"
  print "hash  : ", hash,  "\n"
end

これはなかなか良さそうです。というのも、先の2つの例と異なり、デフォ ルト値の扱いは絶対に必要というものでは無いため、簡単に書けるかどうかが 大きく影響してくるからです。

Perl のような記述の仕方では、意識していないとデフォルト値を用意しな い場合が多くなりがちです。それに対し、Ruby のような記述の仕方は、とて も流れが良く、自然とデフォルト値を用意するようになる事が予測されます。

自然と良いコードが書ける。これは言語仕様としては大きな魅力となりま す。ちょっと乗り換えたくなってきますね。

さて、ここまでで、きれいなオブジェクト指向でいきたいという方はもう 乗り換えを決心された事でしょう。どうみても、Perl よりもきれいです。

しかし、それでもまだ乗り換えないというのがとっぷりはまった Perl ユー ザーでしょう。(私もそうですが)自然に良いコード。よりも、ちょっと工夫し て変な?コード。これが面白いのですから。まだまだ乗り換えるには足りませ ん。

4. 制御構造までオブジェクト

私はこれで乗り換えました。(ついに!)

私はコードをすっきりと書く為に、次のような表現を良く使っていました。 (print でなく変数への代入等でも良いのですが、まあ、例として)

print $no == 1 ? "a" : "b", "\n";

値を返す if 文みたいなものですね。これの欠点は、if..else.. の2つの 値の選択しか出来ない事です(上の例では、"a" 又は "b")。しかし、それでも 結構便利でした。

これに対して、Ruby はそのまま素直に if then else end で書けばOKで した。

print (if no == 1 then "a" else "b" end, "\n")

これはかなり嬉しかったです。なぜなら、if 文がそのまま使えるというこ とは、if then elsif then elsif then else end と、いくつもの条件を使え るという事だからです。しかし、乗り換えを決心?したのはこの次です。そう。 まだ続きがあるのです! 制御構造もオブジェクト。ということは?

print (if no == 1 then "a" else "b" end.tr("a-z", "A-Z"), "\n")

end の後に注目! そう。単なる値を返す文ではなく、正にオブジェクト だったのです。これを逆に Perl で書こうとすると、とりあえずこんな感じで しょうか。

print ((($t = $no == 1 ? "a" : "b") =~ tr/a-z/A-Z/, $t, "\n")[1
..2]);

ちょっと1行にまとめておくには複雑な感じですね。また、ここに "c", "d" なんていう条件分岐が増えたとしたら、もう謎の世界に入ってしまうのは 間違いありません。

では、その謎の世界へ Ruby で入ってみましょう。

print (if no == 1 then "a" elsif no == 2 then "b" elsif no == 3
 then "c" else "d" end.tr("a-z", "A-Z"), "\n")

おどろくほどすっきりです。Ruby ではまったく謎の世界にも入らずに書け てしまいます。さらには、途中に改行を入れられるので、より無理のない書き 方にも出来ます。

print (if    no == 1
         "a"
       elsif no == 2
         "b"
       elsif no == 3
         "c"
       else
         "d"
       end.tr("a-z", "A-Z"), "\n")

とってもスマートに見えますが、なかなか大変な処理です。Perl で書こう としたら、ワンライナーなら謎の世界へ、通常の書き方なら、少なくとも条件 分岐と出力はわけるでしょう。また、小文字大文字の変換の為に、余計な一時 変数も用意するかもしれません。(1つ前の例でもすでに一時変数を使用して いますしね)

これはもう乗り換えるしかありませんでした。とても Perl で対抗する気 にはなれません。

5. 最後に

さて、いかがでしょうか? すぐには乗り換えないとしても、試してみた くはなったことでしょう。最後に、これもしっかりしたオブジェクト指向であ る為に実現されていることだと思いますが、テキスト中へは変数だけでなく、 式まで埋め込み可能になっているという例をあげて終りとします。

#!/usr/local/bin/ruby

print <<END_HTML
Content-Type: text/html

<HTML>
<HEAD><TITLE>ENV LIST</TITLE></HEAD>
<BODY>
<H1>ENV LIST</H1>

<P>#{
  ENV.keys.collect do |key| "<B>" + key + "</B> = " + ENV[key] + "
<BR>\n" end
}</P>

</BODY>
</HTML>
END_HTML

いいでしょう? CGI もこれからは Ruby ですよ。


[INDEX] [Ruby HOME] [TOP]
青山 和光 Wakou Aoyama <pxn11625@niftyserve.or.jp>