関数そのものがファーストクラスではない
やー、Rubyのメソッドはファーストクラスですよ。返り値にできて、変数に格納して演算できて、引数にできるという意味では。
確かに、RubyはPythonやJavaScriptやSchemeに比べると高階関数を陽に使うプログラミング *1 は不格好になる。Pythonなら簡単なのに、
bound_function = obj.hoge bound_function(arg1, arg2, arg3)
Rubyは余計なメソッド呼び出しがくっついて不格好だ。
method = obj.method(:hoge)
method.call(arg1, arg2, arg3)
私もこの点が気にくわなくてまつもとさんに「メソッドがファーストクラスだったらいいのに」と言ったことがある。でも、まつもとさんの考えではすでにファーストクラスということだった。
名前空間
もう細かいところは記憶が定かでないので、以下は私の理解になる。メソッドはただ、名前空間が違うんだ。
既存のメソッドと同名の識別子に値を代入すると、それはローカル変数の初期化になる。けれども、メソッド呼び出しでは依然として元のメソッドを参照する。
p = 1 p p #=> 1
変数の名前空間とメソッドの名前空間は別だ。メソッド呼び出しではメソッドの空間を規定の順序で探索する。値の代入では変数の名前空間を探索する。値の参照においては、ローカル変数をまず探して、存在しなければ引数を持たないメソッドとみなして探索する。
メソッドの名前空間にあるものは呼び出すことができる。変数の名前空間にあるものは呼び出すことができない。ただ、変数の名前空間にあるものに対しては「メソッドを呼ぶ」ことはできる。だから、メソッドあるいはそれに類するものには「それがメソッドの名前空間にあるかのように呼び出す」という call
メソッドが備わっている。
メソッド Object#method
はメソッドの名前空間からメソッドを取り出して、変数の名前空間に持ってくるメソッドだ。一方、 Module#define_method
は逆操作をする。
Rubyの選択
私としてはScheme方式のほうが格好いいとは思う。Rubyの名前空間分離方式っていうのはCommon Lispから継承した代物だよね。たぶん。いや、CL以前のLispのどれかかもしれないけど。
でも、名前空間を一緒くたにすると「selfを省略可能」「引数の括弧を省略可能」というのは難しくなってしまう。Rubyとしては、高階関数を綺麗に書けることよりもこれらのほうが重要だろうと判断しての選択だ、とまつもとさんは言っていた。Ruby 1.9では今のところは
proc.(arg1, arg2, arg3)
はできるようになっているけれども。この点についてはまつもとさんも 苦心している のが見えて、対案がないことにはどうも文句を言いづらい。
結論
というわけで、名前空間の違いですよー、と。
*1:ご指摘の通り、暗に使うのがブロック構文ね