10. ブロックと手続きオブジェクト

クロージャ、やっぱり良く分かっていませんが、10章で、手続きオブジェクトという名前で出てきました。

何でメソッドを使うだけではいけないのでしょうか?それは、メソッドでは出来ないことがあるからです。特に、ひとつのメソッドを他のメソッドに渡すことは出来ません(手続きオブジェクトなら可能です)。そして、メソッドは他のメソッドを返すことは出来ません(手続きオブジェクトを返すことは可能です)。これは単純に、手続きオブジェクト(proc)がオブジェクトであるからで、メソッドはそうでないからなのです。

この説明はなかなか良いと思います。ちゃんと名前を付けてメソッドを作ればいいじゃんと思っていたのが、ちょっとだけ解消されました。
そして、以下この2点から説明が続きます。

(1)手続きオブジェクトを受け取るメソッド

その手続きを、どうやって、どんな時に、何度、呼ぶかのコントロールが可能になります。

ここでAOPの匂いをちょっと感じるわけですが、それは後ほど改めて。

(2)手続きオブジェクトを返すメソッド

もうひとつ、手続きオブジェクトを使ってできるとてもクールな技は、それをメソッド内で作成して返すということです。これによって、 (遅延評価 とか、無限データ構造 とか、 カリー化 とか)といったあらゆるクレイジーなプログラミングパワーを得ることができます。

遅延評価[たらいを後回し]とつながりました。そもそも遅延評価という言葉になじみがないために分かりにくかったのですが、andalsoのことだと考えれば分かったような気にはなりました。

さて、最後に、(1)の省略形として、メソッドに対して(手続きオブジェクトではなく)ブロックを渡すことも可能だよという話が出てきます。その例は、プロファイラで、メソッドの最初に時間を覚えて、最後に時間差を取ってかかった時間を出力することができるという例です。プロファイルメソッドに本来の処理のブロックを渡せばいいので、本来の処理のコードを汚さなくてよいということです。出ましたね。最後の練習問題はロガーです。出ました。
練習問題の解答はこんな感じだと思うのですが(多少アレンジ)、やはり「log」という記述は、ログ出ししたいところに埋め込まないといけないのですよね。ブロックを渡せるので、開始・終了という出し方をできるのは良いのですが、やはりすっきりしない気はします。じゃあやっぱAOPじゃないのと考えてみるわけですが、しかし、アスペクトを織り込めるのはせいぜいメソッドのbefore/afterだろうと考えると、同等のことをやろうとしたらやはり同等以上の記述が必要になってしまうのだろうと、ちょっとクロージャの存在価値に納得したりしています。

$nestingDepth = 0

def log descriptionOfBlock, &block
  puts (‘  ‘ * $nestingDepth) + ‘開始 ‘ + ‘”‘ + descriptionOfBlock + ‘”‘
  $nestingDepth += 1
  block.call
  $nestingDepth -= 1
  puts (‘  ‘ * $nestingDepth) + ‘…. “‘ + descriptionOfBlock + ‘”‘ + ‘ 終了’
end

log ’25回同じ数を足し合わせる’ do
  number = 1

  25.times do
    number = number + number
  end

  log ‘値表示’ do
      puts number.to_s
    end

  log ‘桁表示’ do
      puts number.to_s.length.to_s+‘ 桁’  #  これは、この巨大な数の桁数です。
    end

end

開始 “25回同じ数を足し合わせる”
  開始 “値表示”
33554432
  …. “値表示” 終了
  開始 “桁表示”
8 桁
  …. “桁表示” 終了
…. “25回同じ数を足し合わせる” 終了