Ruby は JavaScript などと違い,整数のような基本的な型もオブジェクトとして扱われます。
また,クラスという〈オブジェクトの振る舞いを規定する仕組み〉さえもオブジェクトです。
そのため,初心者向けの記事でよく
Ruby ではすべてがオブジェクトです。
と書かれます。本当でしょうか?
この問いの答えは,「すべて」という言葉の意味によって変わります。
メソッドやブロックはオブジェクトではありません。
「ええ〜? すべてがオブジェクトって嘘だったのかよっ?!」
いえいえ,これは,Ruby のメソッドやブロックはデータとして扱えないというだけです。Python や JavaScript なんかと違うところですね。
「ええ〜? Ruby ショボイじゃん」
いえいえ,そういうわけではありません。メソッドそのもの,ブロックそのものはデータではないのですが,それをデータ化することはでき,それぞれ Method オブジェクト,Proc オブジェクトと呼ばれます。その名のとおり,それぞれ Method
クラスと Proc
クラスのインスタンスです。当然オブジェクトです。
Method オブジェクト,Proc オブジェクトはデータなので,当然,変数に代入したり,メソッドに実引数として渡したり,そいつが持っているメソッドを呼び出したり,といったことができます。
Proc オブジェクトは,メソッドに実引数として渡せるだけでなく,ブロックとして渡すこともできます。
Method オブジェクトは Proc オブジェクトに変換することもできます。
例を見ましょう。
# 「ブロックパラメーターを 2 乗して返すブロック」を用いて
# 2 乗する Proc オブジェクトを生成
square = proc{ |x| x * x }
# Proc オブジェクトを呼び出す例
p square[3] # => 9
# Proc オブジェクトを map にブロックとして与える例
p (1..3).map(&square) # => [1, 4, 9]
# → 映画「2001 年宇宙の旅」に出てきたモノリスの辺の比率
# 「13 に対する to_s メソッド呼び出し」を表す Method オブジェクトを生成
thirteen_to_str = 13.method(:to_s)
# 引数無しで呼び出すと 10 進で文字列化
p thirteen_to_str[] # => "13"
# 8 進で文字列化
p thirteen_to_str[8] # => "15"
# 2 進,8 進,10 進,16 進で文字列化
# map に & 付きで Method オブジェクトを渡すと,Proc に変換されたうえ,
# ブロックとして渡される。
p [2, 8, 10, 16].map(&thirteen_to_str)
# => ["1101", "15", "13", "d"]
冒頭の問いに戻ります。
「Ruby はすべてがオブジェクト」は,「すべて」の意味合いによっては間違いではないものの,誤解を招きます。
「Ruby はすべてのデータがオブジェクト」と表現すべきでしょう。
Ruby では,変数・定数も演算子も制御構造もデータではないので,オブジェクトではありません。
プログラムもそれ自体はオブジェクトではありません。もちろんプログラムは文字列として表現できるので String オブジェクトで表すことはでき,eval
メソッドによって実行することはできます。