Ruby: Binding

# はじめに
Binding クラス「[class Binding (Ruby 2.1.0 リファレンスマニュアル)](http://docs.ruby-lang.org/ja/2.1.0/class/Binding.html)」には以下のような要約が記述されています。

> ローカル変数のテーブルと self、モジュールのネストなどの情報を保 持するオブジェクトのクラスです。

分かったこと・調べたことをメモしました。

# クロージャ
クロージャを例に Binding を考えていきます。
以下は Ruby におけるクロージャの例です。

```rb
a = 10
p [1,2,3].map {|n| n * a }    #=> [10, 20, 30]
```

ここで、クロージャが以下の３つから成ると考えます。

- 包んでいるもの(クロージャ)。上の例ではブロック「`{|n| n * a}`」
- 包まれているもの(変数)。上の例では変数「`a`」
- 包まれているものがあるところ(環境)。上の例では「変数`a`が定義されているスコープ(明示されてないがここでは main)」

(イメージ図)

![closure1.png](https://qiita-image-store.s3.amazonaws.com/0/60624/5665aa5b-237c-4b1e-3113-49911f3cd3fe.png)

ブロック、変数、スコープとも字義的な面での説明です。
オブジェクト指向の Ruby 世界では、プログラムにあるものはオブジェクトです。
ブロック(クロージャ)は Proc オブジェクトになります。
そして、スコープ(環境)が Binding オブジェクトになります。
変数は Binding オブジェクトに保持されます。


# 変数
Binding オブジェクトに保持された変数が評価されるのは、クロージャの実行時です。
以下の例で、もしも、変数`a` がクロージャ定義時に評価されたとしたら、最後に「`20`」が出力されるはずですが、そうはなりません。

```rb
a = 10                # main に変数`a`を定義する。
f1 = -> { a * 2 }     # クロージャは変数`a`を包む。`a`の参照するオブジェクト「`10`」を包むのではない

a = 100               # 変数`a`の参照するオブジェクトを変更
p f1.()     #=> 200   # クロージャ実行時に`a`が参照するオブジェクト「`100`」を評価
```

以下の例では、ブロック内の変数`b`と main の変数`b`は別物であり、クロージャ実行時にエラーになります。
クロージャが包むのは、クロージャ定義時に定義済みのブロック外の変数です。

```rb
f2 = -> { b * 2 }  # 変数`b`はブロック内の変数

b = 1000           # main に変数`b`を定義する。しかし、ブロック内の変数`b`とは別物。
                   # さらに、クロージャ定義時にはこの変数は定義されてないので、クロージャに包まれていない。
p f2.()   # NameError: undefined local variable or method `b' for main:Object 。。。(;_;)
```

(イメージ図)

![closure2.png](https://qiita-image-store.s3.amazonaws.com/0/60624/eeef84db-33c4-1e1b-b3a0-b8be897e75fe.png)

まとめると、クロージャは、

- 「クロージャ定義時」に定義されているブロック外変数を包む
- その変数が評価されるのは、「クロージャの実行時」

です。

クロージャ定義時に変数を包んでおいて実行時に評価したいが、変数自体はオブジェクトではありません。
そこで、スコープ(環境)をオブジェクト化してそこに変数を保持した。そのオブジェクトが Binding と考えられます。


# 高階関数
Ruby には関数はありません。なので、高階関数もありません。
。。。という細かい話は置いといて、ここでは、feeling 的に「高階関数」と呼んでおきます。

高階関数の例です。

```rb
g = -> { a = 10 ; -> { a * 2 } }  # g は関数 (-> { a * 2 }) を返す高階関数

f = g.()
f.()        #=> 20
```

包まれている変数のスコープ(環境)は g のローカルスコープです。
それ以外は、前述の例と同様です。

高階関数定番(?)の例です。
ここではカウンタは Array にしています。カウントアップ毎に `:x` が増えます。

```rb
g = -> { count = [] ; -> { count << :x } }

f1 = g.()                                # f1 のコール     f2 のコール
f1.()          #=> [:x]                  # 1回目
f1.()          #=> [:x, :x]              # 2回目
f1.()          #=> [:x, :x, :x]          # 3回目

f2 = g.()
f2.()          #=> [:x]                  #                1回目
f2.()          #=> [:x, :x]              #                2回目

f1.()          #=> [:x, :x, :x, :x]      # 4回目
```

(イメージ図)

![closure3.png](https://qiita-image-store.s3.amazonaws.com/0/60624/9e9bc43d-b0ba-a423-b338-5f81aba82af2.png)

クロージャが包むのは定義時の(変数を含む)環境です。(上では g のスコープ)
f1 と f2 が作られる(クロージャ定義される)時、それぞれ g が実行されます。
その度に ローカル変数 count に Array オブジェクトが作られるので、f1 と f2 が包んでいる count(が参照するArrayオブジェクト)は別物になります。

# binding
Binging オブジェクトは Kernel.#binding で取り出せます。
高階関数の例の f1 の Bindig オブジェクトを取り出してみます。


```rb
b1 = f1.binging
p b1.class          #=> Binding
```

Binding#local_variable_get, Binding#local_variable_set でローカル変数の取得、設定ができます。

```rb
p b1.local_variable_get(:count)    #=> [:x, :x, :x, :x]
b1.local_variable_set(:count, [])  # カウンタをリセットしてみる
p f1.()                            #=> [:x]
p f1.()                            #=> [:x, :x]
```

`[]`、`[]=` などにエイリアスすると使いやすいかもしれません。

```rb
class Binding
  alias []  local_variable_get
  alias []= local_variable_set
end

g = -> { a = 0 ; -> { a += 1 } }
f = g.()

f.()           #=> 1
f.()           #=> 2
f.()           #=> 3

b = f.binding
p b[:a]        #=> 3
b[:a] = 10              # 変数`a` の値を 10 にする

f.()           #=> 11
f.()           #=> 12
```

なお、Binding#local_variable_get で取得できる変数はクロージャが包んだ変数です。
クロージャのブロック内(実行時スコープ)の変数は取得できません。

```rb
g = -> { a = 10; -> { x = 2; a * 2 } }
f = g.()
b = f.binding

b.local_variable_get :a      #=> 10
b.local_variable_get :x      # エラー (NameError: local variable `x' not defined for #<Binding:...)
```

Proc 以外のオブジェクトも Binding をもっています。
ただし、binding メソッドは private になっていることが多いようです。

```rb
obj = Object.new
b = obj.send(:binding)   # private メソッドだが、send でなら呼び出せる
p b.class                #=> Binding
```

# 補足
本稿で使ってきた言葉ですが、

-「クロージャ定義時に見えているスコープ」=> 「レキシカルスコープ(lexical scope)」
-「クロージャが包んでいる変数」=>「レキシカル変数(レキシカルスコープの変数)」
-「レキシカルスコープの持ち主(上の例の main や g)」=>「エンクロージャ(enclosure)」

といったりします。
これらは Ruby に限らない用語ですが、どの程度一般的かなど詳しいまではよく分かりません。m(_ _)m
何か調べる際の参考にしてください。

# 余談
ブロックは、レキシカル変数を捕らえてクロージャとして機能したりしますが、実行時(ダイナミックな)スコープを利用する用法もあります。

```rb
v = 10
                       # instance_eval は self をレシーバにしてブロックを評価する
instance_eval do       # ここでは、レシーバが self なので self を self にしている。

  a = 1                # ブロック内(ダイナミックスコープ)の変数
  b = 2                # ブロック内(ダイナミックスコープ)の変数

  p a  #=> 1
  p b  #=> 2
  p v  #=> 10          # ブロック外(レキシカルスコープ)の変数
end

p v   #=> 10
p a   # エラー! (NameError: undefined local variable or method `a' ...)
p b   # エラー! (NameError: undefined local variable or method `b' ...)
```

上の変数 `a`、`b` は instance_eval のブロック内だけの変数です。ブロックを抜けると未定義になります。
現在の環境を一時的な変数などで汚したくない等の場合(私は irb や pry などを使っている時に、たまにあります)は、上のようなことができます。
 
# おわりに
本稿内容の動作確認は以下の環境で行っています。

- Ruby 2.1.5 p273