Rubyの::演算子について

ruby*1では、A::Bという形式の式は、NODE_COLON2という名前になる。::という演算子の式なので、コロンが二つでCOLON2だろうか。とても素直な名前である。::の両端には普通はAとかBとかの定数名を書くが、callメソッドを呼ぶための構文でも使う。

irb(main):001:0> self::(3)
NoMethodError: undefined method `call' for main:Object
irb(main):002:0> (:succ.to_proc)::(3)
=> 4

これいつからある機能なんだろ……

さて、rubyソースコードを見ていると、NODE_COLON3という定義もある。これはコロンが三つ並んだ演算子ではなく、トップレベルの定数を参照するための演算子で、::Objectとか書くと作ることができる。なんで3にしちゃったのかあまり合理的な理由がなさそうな気がする、とても投げやりな感じの、見つけると楽しくなる名前である。*2

なんで、NODE_COLON2を流用するのではダメかというと、

node.h:#define NEW_COLON2(c,i) NEW_NODE(NODE_COLON2,c,i,0)
node.h:#define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0)

となっていて、さらに

parse.y:                        $$ = NEW_COLON2(0, $$);

というのがあって、つまりNEW_COLON3(n)NEW_COLON2(0, n)を区別するためなんだけど、なんで区別する必要があるのかはよくわからない。NODE_COLON2を流用しようとしていろいろ試行錯誤したけどうまくいかなくて、力尽きて良い名前も思いつかずにいつのまにかNODE_COLON3になったんだろうと想像している。

ちなみにNODE_COLONNODE_COLON1は定義されていない。Rubyではコロンはシンボル:symbolやハッシュ{ key: value }に使われるが、それらは字句解析か構文解析の時点で、他の構文に取り込まれてしまう。

*1:Matzの実装したRuby処理系の一つ

*2:合理的でなくてかっこよくもないものを見つけると、さぞかし苦労したに違いないと思って、ちょっと楽しくなる。