RubyがPHPに勝つにはメソッド呼び出しのための新しい演算子が必要
PHPerがRubyを触り始めて最初に不機嫌になるのは、空文字列が偽ではないことだ。つまり、PHPなら「if ($var)」で済むのが、Rubyだと「if !var.empty?」と書かなければならない。これでPHPerは不機嫌になる (まあ気持ちは分かる)。
if ($var) ... # PHP if !var.empty? ... # Ruby
それだけならいい。もし値がnilである可能性があるなら、Rubyでは「if var && !var.empty?」と書かなければいけない。この時点でPHPerは不機嫌どころかブチ切れる。なんでこんなに書かなきゃいけないんだ!? PHPなら「if ($var)」で済むのに!! SHIIIIT!!
if ($var) ... # PHP if var && !var.empty? ... # Ruby
ここで、「空文字列が偽になるような言語仕様こそクソだ!」と言い出したら、あなたも訓練されたRubyistである。PHPerがブチ切れているのは、「値があるかどうかを調べる」という非常にありふれたことをいちいち「var && !var.empty?」のように長々と書かなきゃいけないというストレスに対してであり、空文字列が偽かどうかということに対してではない (そもそも大半のPHPerは言語仕様の細部に興味がない)。そのことに気づかず、「空文字列が偽になる言語こそクソ」と言い出すRubyistは論点がまるで分かってない。
この問題に対し、DHHはRuby on Railsでひとつの解決策を示した。Object#blank? である。これを使うと、値がnilかどうかを気にする必要がなくなった。PHPの「if ($var)」よりは冗長なものの、「var && !var.empty?」よりは随分な進歩である。
if !var.blank? ... # Ruby on Rails if var.present? ... # 最近はこうも書けるらしい
ただし Object#blank? をサポートするには、Object だけでなく Array や String など多くの組み込みクラスにメソッドを追加しなければいけない。#blank? をサポートするためだけに多くの組み込みクラスに変更を加えるのはちょっと大げさだし、ActiveSupportを使うと #blank? 以外も定義されてしまうし、なによりCGIでは重くて使えない。
また Rails 2.3.2 からは Object#try() が導入された。これを使うと、次のように書くことができる (var が nil なら何もしない、nil 以外なら empty? を呼び出す)。
if var.try(:empty?) # var が nil 以外のときだけ empty? を実行
しかしこれもActiveSupportが必要だし、なにより初心者にはわかりにくい。たかが「値があるかどうかを調べる」だけなのに、Object#try みたいなトリッキーなのが必要になる時点で何かが間違っている。
もっと簡単な方法を考えてみると、NilClass#empty? を定義する方法が思いつく。これは実に手軽な方法であり個人的にもお気に入りなのだが、なぜかRubyには取り入れられない (まあ「nil が空ってどういう意味?」と聞かれたら答えられないのも確かではあるが)。
class NilClass def empty? true end end ## 使い方 if var.empty? ... # var が nil または空なら
というわけで、PHPでは「if ($var)」で済むことが、「値があるかどうか」を調べるというただそれだけのことが、いまだにRubyでは長々と「if var && !var.empty?」と書かなければいけない。これではPHPに勝てない。いくら他の部分が勝っていても、こんな基本的なところで負けていては、いつまでたってもRubyはPHPの後塵を拝したままだ。Rubyが本気でPHPに勝とうとするなら、こんな弱点があってはだめなのだ、相手に付け入る隙を与えてはだめなのだ。
じゃあどうすればいいか。ここでは Object#blank? でも NilClass#empty? でもなく、レシーバがnilでないときだけメソッドを実行する新しい演算子を導入することを提案したい。これはもともと、「<%=h user.group ? user.group.name : nil %>」とか「<%=h user.group.name if user.group %>」と書くのが面倒だったので思いついたことではあるが、今回のような「var && var.empty?」でこそいちばん活躍するはずだ。
## 「->」が新しい演算子。 ## var が nil でないなら var.empty? を実行し、nil なら nil を返す。 if var->empty?
ただ「->」はRuby1.9から別の目的で使われるそうなので、ここではGroovyの「?.」に倣って「.?」を提案しておく。
## 「.?」が新しい演算子。 ## var が nil でないなら var.empty? を実行し、nil なら nil を返す。 if var.?empty?
これでようやく、RubyもPHP並みに短く書けるようになった。実際には「if ($var)」で済むPHPにはまだ負けているのだが、このくらいなら十分対抗できる。もうPHPに付け入る隙を与えはしない。
もちろん、新しい演算子が実際に導入される可能性はかなり低い。しかし、Rubyは変化を恐れないとMatz大神が公言しているので、可能性がないわけではない。そのためには、新しい演算子の導入を皆が望む必要がある。需要がないものは導入されない。需要があっても導入されるとは限らないが、まずは皆が声をあげないことには始まらない。
そのような考えから、今回のエントリを書いてみた。現状のRubyではまだPHPに負けている部分がある。「if var && !var.empty?」は「if ($var)」より長くて面倒くさい。その事実を素直に認めた上で、メソッド呼び出しのための新しい演算子が導入されるよう、地道に活動していきたい。そのためにも、ご賛同いただける方はぜひブックマークをお願いしたい。
* * * *
一方、ロシアは Kernel#empty? を定義した。
def empty?(val) val.nil? || val.empty? end ## 使い方 if empty?(var) ... # var が nil または空なら if !empty?(var) ... # var に値があるなら