« MySQLのテーブル一覧、create table一覧、show index一覧、レコード数の一覧を取得する。 | トップページ | PerlのDBIでMySQLにShift JISの日本語のデータを挿入する。 »

2010年1月24日 (日)

Perlへの懺悔

ここ数年Rubyを使っています。
Rubyこそ最高のスクリプト言語だと思っていました。
Rubyの名前の由来もよりよいPerl (pearlは6月の誕生石、ruby は7月の誕生石 )
という意味を意識してのものです。
そのため、Rubyが盛隆になった今、Perlを使っている人は、Rubyに乗り遅れて、Perlの知識にしばられているだけ。そう思っていました。

でも、その思いは間違っていました。

PerlにはPerlのよさがあり、Rubyにけっして劣っていない。と最近そう確信するにいたりました。
そこで懺悔の意味をこめて、Rubyに比べたPerlのよさを述べたいと思います。

1.参照回数によるオブジェクト破棄のため、破棄時が明確である。
perlは対象のオブジェクトのリファレンスがなくなった時に破棄が実行されるのに対し、rubyはGC(ガベージコレクター)による破棄のため、破棄がいつ行われるかわかりません。
いつ行われるかわからないというのは、2つの点で問題があります。

   a.メモリが必要以上に消費されてしまう。
   b.リソースの開放処理を自分で記述する必要がある。

a.に対してですが、最近Rubyでバックアップツールを作って、動かしていたのですが、4Gあるメモリーがほとんどバックアップツールによって使われてしまい、他のプログラムの動作に支障がでたということがありました。
バックアップツールはファイルを読み込む処理はあるものの、一時変数に読み込んだデータを代入しているので、関数が終了した時点でそのメモリーが開放され、メモリーが使い果たされることはないと思っていたのですが、関数を抜けた瞬間にGCが動くと言うわけではないため、メモリー使用が蓄積されてしまいました。そのため、毎回GC.startというメソッドを呼び出すようにしたところ、メモリの使用量が一定になりました。

b.に関しては下記のソースを比べてみてください。
perlバージョン

 use DBI;

sub print_simple01{
  my $dbh = DBI->connect('DBI:Mysql:test', 'testuser', 'testpwd');
  my $sth = dbh.prepare('select * from simple01');
  $sth.execute
  while(my @row = $sth->fetchrow_array) {
    print "@row\n";
  }
}

rubyバージョン

 require 'dbi'

def print_simple01
  dbh = DBI.connect('DBI:Mysql:test', 'testuser', 'testpwd')
  sth = dbh.prepare('select * from simple01')
  sth.execute
  while row=sth.fetch do
      p row
  end
  sth.finish
  dbh.disconnect
end

ほとんど変わらないのですが、rubyバージョンには、sth.finishやdbh.disconnectの文があるのに対し、perlにはありません。
なぜかというとperlにはオブジェクトが廃棄される際にDESTROYというメソッドが呼び出されることになっているので、その中でリソースの開放処理を行っているため、必要ないのです。
rubyの場合にもオブジェクト削除時に処理を走らせることができるにはできるのですが、いつ実行されるかわからないため、リソースの開放処理には使えません。そのため、自分でリソース開放処理を行う必要があります。
もちろん、rubyの開発者はそのことを承知していて、その問題をブロックにより解決しています。例えば次のようになります。
ruby ブロックバージョン

 require 'dbi'

def print_simple01
  DBI.connect("dbi:Mysql:test:localhost", "testuser", "testpass") do |dbh|
    dbh.prepare('select * from simple01') do |sth|
      while row=sth.fetch do
          p row
      end
    end
  end
end

確かにリソースの開放処理がいらなくなったため、スマートになったと言えます。その代わりネストが深くなっています。
リソースを複数同時に使いたい場合等に複雑になってしまうため、perlの参照回数方式のほうがこの場合はいいように思えます。
rubyが参照回数方式ではなく、GC方式にしているのは、rubyの拡張ライブラリを書きやすくするためだそうです。
このあたりは開発者をいかに楽にするかというrubyの思想だから、それでいいと思います。

2. 高機能のオブジェクト指向機能が使える。
ここは、えっと思うところかもしれません。
確かにPerl5に組み込まれているオブジェクト指向の機能は無理やり感があって、使いづらい思いをした人も多いと思います。でも、言語にオブジェクト機能が組み込まれていないからこその柔軟性がPerlにはあります。
Mooseというモジュールです。
Mooseは、各メンバ変数ごとに型を指定したり、書き込み、読み込みの許可を指定できたり、デフォルト値のセットに関数を指定できたり、遅延評価できたり、フックをかけたり、強制的に型変換をできたり、またロールを使ってインターフェースプログラミングを支援したりと高機能なオブジェクト指向機能を提供してくれます。
高機能な代わりMooseは重いです。でも互換・軽量版のMouseというモジュールもあります。Mouseは10年前のバージョンであるperl 5.6でも動作します。
要件に応じて取捨選択ができるのです。処理速度が重要な場面なら、それらのモジュールを使わなければいいのです。

以上他にもあると思いますが、私にはすぐに思いつきません。

ここで何でいまさらPerlのよさに気づいたのかを説明します。

業務上の都合でこの数ヶ月perlを使わざるを得ませんでした。
;抜けや$つけ忘れ、宣言忘れのエラーが出まくる、モジュールの最後に1;を書き忘れて、動作がおかしい、mockやfixture等の仕組みがないからテストがしにくい、irbがない、@a[1]で動作がおかしいのにエラーにならない、ハッシュスライスの文法が直感的でない、inspectがないから、printで出してもHash,Arrayなどのあまり意味のない情報が出力される等散々最初は愚痴りました。

初めに立てたスケジュールも大幅に狂いだし、どうしようかと思ったそんな時、iPhoneのアプリでlearning perlが600円とういう安さで提供されていたため、通勤中にでも読もうと買ってみたところ、これが本当にいい本でした。

$はsclarのsで@はarrayのaからだよのところから、なぜモジュールの最後に1;をつける必要があるのか(もし条件にあわなかったら、そのモジュールを読まないという機能を提供するため)等、なぜが書かれていました。

perlを知ることはLarry Wallを知ることと言われるように確かに文法はrubyに比べて複雑で、時々トリッキーです。でもそれぞれには、理由があり、納得できれば気にならなくなります。

また、Perlのコードは可読性が低いとよく言われます。実際自分でPerlで書いた2ヶ月前のコードを読んでさっぱり意味が解からなかった経験があり、私もずっとそう思っていました。
でも最近、他人が書いたRubyやPerl、自分の書いたRubyやPerlのプログラムを読んで、決してPerlのほうがRubyより読みにくいと言えないと確信しました。

例えばCでプログラムを書くときは、まず設計をしてからプログラムを書きます。でもスクリプト言語を覚えたての時は、いちいちコンパイルする必要も無いため、Try&Errorでガリガリとコードを書いてしまい、後々なぜそういう処理をしたのかが思い出せないのが、自分の書いたコードでも読みにくい原因だと思います。

Rubyでそこそこの規模のツールの開発やRailsによるWebアプリの開発を経験してきた今は、保守を考えたモジュールやメソッドの分割に慣れ親しみ、Perlで書いてもRubyで書いても可読性は全然変わりません。

Perlなんてと思っている方は、是非「初めてのPerl」,「続・初めてのPerl」,「モダンPerl入門」を読んでみてください。
きっと、Perl、悪くないよね。って日が来ます。

|

« MySQLのテーブル一覧、create table一覧、show index一覧、レコード数の一覧を取得する。 | トップページ | PerlのDBIでMySQLにShift JISの日本語のデータを挿入する。 »

perl」カテゴリの記事

コメント

> Moose
http://doodle.rubyforge.org/
全く同じではないですが,これとかどうでしょうか?

投稿: tama | 2010年1月25日 (月) 04時50分

>> tama さん

doodle,知りませんでした。まだ開発途上のようですが、かなりよさげです。
教えていただき、ありがとうございました。

投稿: takeshy | 2010年1月25日 (月) 13時17分

ヒューマンリソースは有限である以上、似たようなモノが複数ある場合後発を世に出した人は非難されるべきです。昔ベーシックなんかのインタプリタ開発合戦の後に超小型言語開発合戦になった日本。そのノリでルビーが出てしまいました。日本の恥です。トチ狂った松江市がルビーをメジャーにするべくあがいていますが、絶対的なメリットが無いルビーに勝算はありません。なまじルビーで構築されたアプリケーションシステムの将来にわたってのメンテに税金が浪費される事になっても松江市の職員誰一人責任を取らないことは明白。

投稿: よたろ | 2011年12月24日 (土) 17時33分

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/68673/47380026

この記事へのトラックバック一覧です: Perlへの懺悔:

« MySQLのテーブル一覧、create table一覧、show index一覧、レコード数の一覧を取得する。 | トップページ | PerlのDBIでMySQLにShift JISの日本語のデータを挿入する。 »