Time to Read
3分
RubyKaigi とか色々あって、ふと、僕がプログラミングを始めたころのことを何となく思い出したので走り書きしておきます。特に PHP に関しては記憶が曖昧なところがおおいので、 PHPer モヒカン族によるツッコミを歓迎します。
1) 配列とハッシュが違う
PHP においては、配列も連想配列もすべて array()
と言う関数で生成する。むしろ、配列というものがキーを数字にしているだけの連想配列と言う位置づけだと思う。
Ruby ではもちろん、主たるコレクションには Array
と Hash
の二種類が存在し、区別される。最初はこの区別に若干戸惑いを覚えた。
ちなみに Python だとリスト・タプル・辞書ともっと増えるわけで、Javaのコレクションクラスに至ってはさらに多いし、この辺はどの実装が正しいとか適切とかではなく慣習なのかなあ、と思ったりする。
2) 型(クラス)がより厳格
PHP では OK な以下のような書き方:
1 2 3 4 5 | <?php $i = 1; echo "count" . $i; //=> count1 ?> |
Ruby ではエラーになる。
1 2 3 | i = 1 puts "count:" + i #=> TypeError: can't convert Fixnum into String |
ここ、最初のアプリケーションを CGI でガリガリと書いたんだけど、結構ハマった……。むろんこのあたりの型のチェックは厳密な方が、変なバグを生みにくいという側面もあるかもしれないので、一概にどちらがいいとは言えないかも。
3) ClassName#Method
という書き方に違和感があった
たとえばオンラインの Ruby リファレンスマニュアルなど、そこかしこで見られるこの書き方の習慣、慣れるまで少し違和感があった。 PHP ではオブジェクト指向的に書けるとはいえ、基本的にグローバルに関数が定義されていて、あるメソッドがあるクラスに属していると言う感覚が非常に薄かったこともある。
4) for を使うことがほとんど無い
そもそも僕が Ruby を始めたのは、
1 2 3 | 3.times do |i| puts "hello" end |
3 回繰り返すときに「3.times
」と書ける面白さにえらく感動したからで、実際使ってみると for
と言う予約語は確かに存在するけれど、繰り返すときは前述の times 、配列をぶん回すときは普通に配列自身の each を用いればいいので使わないな、むしろ使わないってなんて楽なんだろう、ということを思ったりした。
5) RubyGems が便利
PHP にももちろん PEAR 、 PECL があるけれど、(少なくとも3年前の段階では)充実度が非常にいまいちだったし、実際フレームワークといったって各フレームワークごとに同じような機能を再発明して添付していたり、が多かったような気がする。
Ruby では、ちょっとした機能の実現(Zip圧縮とか、RDBMSへの接続とか、画像加工とか)をしたいときは、まず gem の情報を調べて、RubyGemsでインストールする、その開発サイクルが新鮮に感じられた。cpanとかだともっとすごくこんな感じなのかな?
6) 「偽」になるのは nil と false だけ
この一貫性のあるルールは楽だった記憶がある。いま、 "0"
とか 0
とか ""
とか、どの値が PHP において「偽」扱いだったのかよく思い出せないお……。
7) 基本的に「参照渡し」「値渡し」である。ただし、「オブジェクト自体の参照」が「値渡し」されるので、参照渡しのように扱える
PHP においてはなんかこの辺のルールが中途半端だったような気がしていて、「&
」とかよく分からない記号も出てくるし、いくら説明を呼んでもまるでしっくりこなかった記憶がある。
Ruby においては、 Integer 、 Symbol 、そしてインスタンスが一つしかない True/False/NilClass だけが値渡し、それ以外のオブジェクトはみんな参照渡しになる。
Rubyでの参照渡し の記事にあるように、扱いとしては「値渡し」のようです。ただし、オブジェクトの参照(ポインタ)自体が値渡しされる感じのようで、「参照渡し」で実現したい破壊的操作などを行うことは可能です。ということらしい。(修正 @ 7/31 9:08)
ともかく、破壊的操作の影響を避けて値だけ渡したいなら Object#dup
等を使う。要するに明示的にコピーするということ。こうして一貫しているので、
1 2 3 4 5 6 7 8 9 | arr = [1, 4, 3, 2] def array_sort!(arr) arr.sort! end array_sort!(arr) arr #=> [1, 2, 3, 4] |
「オブジェクトは本当はメモリに乗っかってるんだよ」と言う感覚が身についた気がする。まあこの辺は情報処理試験で勉強した C の知識も影響しているとは思うけれど。
「&」と言う記号はどちらかと言うとブロックとProcオブジェクトの変換時に使用される。
まとめると、今の認識としては以下のような感じである。
というか、値渡し参照渡しってレイヤーが低くて分かりにくいし、 Ruby ではその辺は普通にコード書いてる分には見えなくしちゃった、というのが正しいのかもしれない、、、名前はともかく、immutableでなければオブジェクト自体を渡してるんだよ、みたいな
8 ) ブロックが便利
上述のようなイテレータはもちろん、ファイルを開くとき、書き込むときにも、 PHP であれば
1 2 3 4 5 6 | <?php $filename = "/usr/local/something.txt"; $handle = fopen($filename, "w"); fwrite($handle, "Write Test"); fclose($handle); ?> |
fopen()
と fclose()
が必要だ(fclose()
は明示的に実行しない場合もあるかもしれない)。
Ruby は、明示的なクローズをしなくても、
1 2 3 | File.open("/usr/local/something.txt", "w") do |f| f.write "Write Test" end |
「ブロック」と言うかたちでファイルの開け閉めを表現できるのはすっきりしているなあ、と思ったのだった。
(元々の例は読み込みでしたが、ふつう PHP では file_get_contents という便利関数を使用するそうなので書き込みに修正 @ 7/31 14:47)
9) Symbol ってなんなの?
今でも実はあまり理解していないかもしれないが、最初 Ruby において String と Symbol の両方が存在する意味が分からず、 Hash のキーにも String を使うことが多かった。
今ではすっきり書けるメリットも大きいし、 Hash のキーには immutable な Symbol が良いのでは? とも思うので普通に Symbol を使っているのだが、実は例えば
1 2 3 | ha = {"foo" => 1, "bar" => true} ha.keys.first.reverse! #=> TypeError: can't modify frozen string |
このように、 Hash のキーになった文字列はその場で freeze されるようなので、それなら Symbol であるメリットの一つが無くなるような? あれれ? と思ったりもした。
10) オブジェクト指向って便利だし、メソッド名その他が納得感がある
たとえば MySQL の利用一つとっても、
1 2 | db = Mysql.init.real_connect('localhost', 'udzura', 'sekrit', 'some_db') db.query("SELECT * FROM users WHERE id = 1") |
たくさんの謎関数(最近のmysqliには謎関数が無くてオブジェクト指向みたいだけれど、そうは言っても入門書においては謎関数を書かせるやり方が主流だった3年前……)を覚えなくても、 db 変数に入っている Mysql オブジェクトに対して操作メッセージを呼べば良いだけで、しかもそのメッセージ(メソッド)も納得感のあるわかりやすい名前ばかりで、書いていて楽しくなるような感覚があった。そう、僕も「名前重要」にヤられてしまった一人である。
むかし(確か)日経ソフトウェアに連載していた Rubyをめぐる冒険 に以下のような一節があった。
以前,ある文字列の中に特定の文字がいくつあるのかを調べたいときがあった。「”ABAC”の中にAは何文字あるのか?」という問題だ。
文字を一つひとつ区切って調べようとしたとき,ふと思った。「何文字かを数えるなら英語でcountだ」と。そして,Rubyには,既にそんなメソッドがありそうな気がした。早速マニュアルも見ずに,次のようなコードを記述してみた。
puts "ABAC".count("A")
すると,驚いたことにこのコードはきちんと動き,「2」という値を表示した! つまり,僕が勝手に想像した「count」というメソッドはちゃんと存在したのだ。
まさにこの感じを、僕も体感したわけで。そうして最初「Rails ってのが流行ってるらしいしやってみんべ」だった僕がどんどん Ruby にはまることに……
PHP もオブジェクティブに書けるとはいえ、 Ruby は生まれつきのオブジェクト指向で、しかも「いかに楽しくプログラミングができるか」と言うところを考えつづけて開発されてきた側面もあるわけで、そういうわけで Ruby の「オブジェクト指向を楽しめる」力は大変大きいと思ったのだった。
* * *
僕は PHP と Ruby どちらが優れている、と言う話しには触れないし、個人的には PHP にはたくさんの優れたプロダクトがあって素晴らしいと思う。
ただ、上のようにまとめていると、最初は戸惑っていた違いも、結局「慣れ」で吸収できる程度のものだったと思うし、やっぱり Ruby には、「書いていて楽しくなる工夫」が詰まってるんだな~と気づき、そういうところが僕にとって何より魅力なんだな、と改めて自分の中で整理できた。