「プログラミング言語Ruby」を読まなくてもよいのは誰か

投稿者 akira 2009-01-29 11:36:00 GMT

一昨日になってようやく入手できたプログラミング言語 Rubyプログラミング言語Ruby[rakuten]を、Ruby 1.9.1RC2とそのNEWSファイルを手元に置きながら読んだ。

少々乱暴な言い方になるかもしれないが、この本は以下のような人には用のないものだと思う。

  • Ruby 1.9.xもRuby 1.8.xも十分に理解できている
  • Ruby 1.9.xをしばらくは使うつもりがなく、自分が使う範囲においてRuby 1.8.xに不明なところはない
  • Rubyの経験がなく、その他のオブジェクト指向言語の経験および知識もない
  • プログラミング経験がなく、これからプログラミングの学習を始める

この本はRubyそのもののかなり詳しい解説書である。入門書ではない。一応は簡単なところから入る形になっているのだが、大部分はすでにRubyを使っていて、ちょっとしたことなら困らない程度の知識があることを前提としている。つまり、Rubyをより深く知るための解説がある。プログラミング自体の入門者は別の本(おそらく初めてのRuby[rakuten]やたのしいRuby[rakuten]など)が適切だろう。プログラミングの経験はあるが、Rubyやその他のオブジェクト指向言語に馴染みがないという人は、チュートリアルなどをこなしてからにしたほうがよさそうだ(これに当たる人には「用のない」とまでは言えない)。

全体的にはRuby 1.8系をベースにしていると思われるが、Ruby 1.9.1での状況についてもそれなりのスペースを当てている。私は1.9.1での新しい機能や1.8系との非互換に特に注目して読み進めたのだが、たとえば多言語化関係のような大きなトピックにはそれなりのスペースがあてられている。込み入ったところではどうかは分からないが、多言語化の仕様・実装の推移をほとんど追いかけていなかった(追いかけられなかった)私でも、その基本的な使い方や注意点がわかるのに十分な記述はある。細いところでも、メソッドの追加や削除についての補足があり、場合によっては新しい機能(たとえば->(){}やノンブロッキングIOなど)の詳しい使い方が示されてもいる。

参考までにRuby 1.9.1RC2のNEWSファイルとの対応状況をごく簡単にまとめてみたところ、少なくとも六割くらいはカバーされていることが分かった。NEWSファイルの記述は粒度がまちまちだということもあって、実のところ、読んでみた印象よりもこれは低い数値だった。とはいえ、前述した通り大きなトピックについては十分にカバーされている。

Ruby 1.8系から変化のない部分についても(もちろん)詳しい説明がある。思いもよらぬ機能や動作があることをこの本によって知ることができた。たとえばこんなことである。

  • f(3+2)+1f (3+2)+1の違い
  • p {1=>2}p 1=>2で正しいのは?
  • to_sto_strの違い
  • initialize_copyの機能とdupclone
  • and&&の使い分け方
  • ensure節の中でreturnすると例外が消える
  • Ruby 1.9.1のRange#include?の遅さ
  • Ruby 1.9.1のスレッド実装では複数スレッドが同時に実行されることはない

これらは、このような細いところまで説明しているという単なる例だ。一方で、HashやNumericなどと馴染むような標準的なクラスの作り方(7.1節)に十分なページ(20ページ)があてられてもいる。そうかと思えば「関数プログラミング」と題して10ページほどの解説を展開したりする(6.8節)。

そのようなわけで、Ruby 1.9.1をこれから始めようというのならおすすめだし、Ruby 1.9.1を使わないにしてもRuby 1.8.xで不明な点があるなら(そして他の書籍などが手元にないなら)やはりおすすめできる。結局のところ、多くのRubyユーザにとって読んでみて損のない本だと思う。ただし、何かの作業のための実用的な(というのは外部コマンドを起動したり、特定の形式のデータ処理をするような、実務的な)プログラミングのためのヒントは限られたものしかないため、そのような意味での情報を求めている人は別の書籍なりなんなりと比較してみたほうが良いだろう。

王狼たちの戦旗

投稿者 akira 2009-01-26 11:55:00 GMT

七王国の玉座を引き続き読み、二部にあたる王狼たちの戦旗〈5〉―氷と炎の歌〈2〉 (ハヤカワ文庫SF)王狼たちの戦旗5(氷と炎の歌2)[rakuten]まで進んだ。

ファンタジー要素は少しずつ出てきている。でも全体的に見ると歴史物なのかなと思えてくる。思惑が交錯しまくって裏切りとか裏切りと裏切りとか。

氷と炎の歌3は取り寄せを依頼していて、すでにお店に届いているようなので明日くらいには入手できそう。ただ、ここからハードカバーなんだよねえ。どうやって読もうか。

cafe emo. espressに行ってきた

投稿者 akira 2009-01-23 06:30:00 GMT

この間は通り掛かっただけになってしまったcafe emo. espressのスポット営業がタイミングよくあったので行ってきた。

横浜関内、cafe emo. espressoのカプチーノ横浜関内、cafe emo. espressoのエスプレッソ

たのんだのはカプチーノとエスプレッソ。ただし、本来の店主さんではない方によるもの。これはこれでおいしかったけど、通常営業が再開されたらまた行ってみたい。が、小さなお店でもあり、煙を避けがたいのが難しいところ。とはいえ、あのエリアでこの種のお店はなかったので。

Ruby 1.9.1RCとRuby 1.8.7のERBの比較

投稿者 akira 2009-01-21 08:07:00 GMT

Ruby 1.8.7-p72、Ruby 1.9.1RC1、Ruby 1.9.1RC2でERBの動きを見みた。というのはevalがかなり遅くなるようだったので。

[Ruby 1.9.1RC1]
          times  0.000000   0.000000   0.000000 (  0.004078)
           eval  0.270000   0.000000   0.270000 (  0.266262)
        ERB.new  5.420000   0.000000   5.420000 (  5.414356)
     ERB#result  3.060000   0.000000   3.060000 (  3.064426)
 ERB#def_method  3.940000   0.000000   3.940000 (  3.927113)
    method call  0.160000   0.000000   0.160000 (  0.157707)

[Ruby 1.9.1RC2]
          times  0.000000   0.000000   0.000000 (  0.004093)
           eval  0.270000   0.000000   0.270000 (  0.268327)
        ERB.new  5.390000   0.010000   5.400000 (  5.385314)
     ERB#result  3.080000   0.010000   3.090000 (  3.073989)
 ERB#def_method  3.940000   0.000000   3.940000 (  3.939181)
    method call  0.160000   0.000000   0.160000 (  0.157465)

[Ruby 1.8.7-p72]
          times  0.000000   0.000000   0.000000 (  0.003282)
           eval  0.060000   0.000000   0.060000 (  0.048032)
        ERB.new  6.740000   0.000000   6.740000 (  6.747736)
     ERB#result  1.430000   0.000000   1.430000 (  1.422354)
 ERB#def_method  1.650000   0.000000   1.650000 (  1.657660)
    method call  0.170000   0.000000   0.170000 (  0.162981)

benchmark/driver.rbのまねをしてループを補正している。evalの補正もしたほうがよいのかなとも思ったけどしていない。まあ、補正といっても埋もれるくらいの感じなのであまり影響なさそうだが。

Ruby 1.9.1〜を構成する三つのバージョン

投稿者 akira 2009-01-17 13:33:00 GMT

Ruby 1.9.1RC1の標準的な$LOAD_PATHは以下のようになる。

/usr/local/lib/ruby/site_ruby/1.9.1
/usr/local/lib/ruby/site_ruby/1.9.1/i686-linux
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/vendor_ruby/1.9.1
/usr/local/lib/ruby/vendor_ruby/1.9.1/i686-linux
/usr/local/lib/ruby/vendor_ruby
/usr/local/lib/ruby/1.9.1
/usr/local/lib/ruby/1.9.1/i686-linux

ここで気になるのは末尾付近の1.9.1である。

Ruby 1.8シリーズまではこの部分に入るのは1.8のようにマイナーバージョン(X.Y.ZのY)までであった。これはマイナーバージョンレベルでの互換性が保たれる――か、少なくともそのようにする意志があると考えられる。ところが今回のリリースされた実装ではこの部分にフルバージョン(X.Y.Zのすべて)が埋め込まれている。となると1.9.1以降ではそのレベルで、つまりマイナーバージョンアップされるごとにすべての互換性が失われるのだろうか。

もしそうであるならばとても困ったことになる。というのは、将来リリースされるRuby 1.9.2にはバグ修正やことによってはセキュリティ修正が含まれているはずであり、通常はできるだけ早くバージョンアップすべきものとなる。ところが、前述のような事情においては互換性の点からRuby本体以外とは別にインストールしたすべてのコード(Rubyで書かれたコードとC言語などで書かれた拡張ライブラリの両方)が利用できなくなる心配があり、マイナーバージョンアップであってもおいそれとは実施できない。ついでに言えばすべてのコードが$LOAD_PATHから外れてしまうことにもなる。

そのような危惧をもって質問したのが[ruby-dev:37748]である。

実はこのメールを送る前にIRCで意図を尋ねていたのであって、質問というよりも確認を目的とするものとなってしまっているのだが、ともあれ結論としてはそのような心配はない。

現在の実装では$LOAD_PATHにRuby本体のフルバージョンが埋め込まれているのであが、それは単にコード側が間に合っていないことによるそうだ。本来の意図に従うと$LOAD_PATHに含まれているのはRuby言語レベルでの互換性を表す文字列である。Ruby言語レベルでのAPIバージョンとも言える。これはRuby本体のバージョンとは別のもので、Ruby言語レベルで互換性がなくなったときに上がることが予定されている。したがって、Ruby 1.9.2がリリースされた際、互換性が保たれていれば$LOAD_PATHには1.9.1が含まれることになる(保たれなければ1.9.1以外の何かになる)。

このRuby言語のAPIバージョンは、バイナリ互換性を表すものではないが、$LOAD_PATHの中の拡張ライブラリ用のパスに対しても同様に埋め込まれている。これはRubyで書かれたライブラリから拡張ライブラリをrequireしているものがあるためで、相互に関係し合うことを考えて一方の互換性がなくなったときには他方でも互性換がなくなったものとみなす。

バイナリ互換性についてはlibruby.soのsonameなどによって運用されることになる。現在の実装ではマイナーバージョンまでを含んだlibruby.so.1.9などが設定されるようになっている(コンパイラに-Wl,-soname,lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR)が与えられている)が、これはおそらくRuby 1.9.1リリース時には変更されるものと予想される。

まとめるとRuby 1.9.1以降では、Ruby本体のバージョン、Ruby言語レベルでの互換性を示すバージョン、Rubyインタプリタのバイナリ互換性を示すバージョンという三つのバージョンが運用されることになる。後二者に変化があればRuby体本のバージョンは上がるが、Ruby本体のバージョンが上がっても後二者が変わらないことはありうる。なお、バイナリ互換性については1.9シリーズの中のどこかで失われる可能性があるそうだ。

ところで$LOAD_PATHの中の/usr/localの部分はconfigure--prefixで指定したパスであり、/usr/local/libに続くrubyの部分は同じく--program-prefix--program-suffixでの指定を加えたRubyインタプリタ名である。たとえば--prefix=/opt --program-suffix=1.9.1rc1としたならば、$LOAD_PATHの最初のエントリは/opt/lib/ruby1.9.1rc1/site_ruby/1.9.1となる。

このように$LOAD_PATHにRubyインタプリタの名前が入ることで何か困るということは、それを知って運用している分にはあまりないと言えるかもしれない。だが、これまでたとえばRubyコマンドにバージョンを付ける形でインストールしていたというような環境では、上述の三つのバージョンの問題とは別に、マイナーバージョンアップごとに$LOAD_PATHの内容が変わってしまう問題が生じることになる。しかもこの部分の文字列を指定する方法は提供されておらず、これを回避するにはソースコードに手を加えるしかない。

それではいくらか不便であるためconfigureで指定できるようにしてはどうかと提供してみたのが[ruby-dev:37749]である。実際にはRubyライブラリと拡張ライブラリのそれぞれの場所を個別に指定できるようにしているつもりで、/usr/share/usr/libの使いわけを意識したものでもある。とはいうものの、アーキテクチャ依存のRubyコードを、アーキテクチャ用のパス(/usr/local/lib/ruby/i686-linuxなど)に配置するといった認識が一般にあるとは思えないので(mkmf.rbにも対応はないと思う)、その入口くらいにしかならないかもしれない。