Ruby の private と protected 。歴史と使い分け

## 概要
Ruby の private と protected の歴史と使い分けについて説明します。

いろんなところで断片的に書かれていることなのですが、有益な情報を
一箇所に集めると自分の理解が深まりそう＝＞他の人にも役立つかな？
と思ったのでまとめてみました。

具体的には、伊藤淳一さんのブログ・るりま・Rubyメーリングリストの内容を
一箇所にまとめた上で、私が書いたサンプルコードを少し足した内容になっています。

ちなみに Java や C# 畑の人が Ruby の private / protected を使って驚いた、
的な情報が多いですが、私も例にもれず Java => Ruby 勢で驚いたパターンです。

## Java の private と protected
* public => どこからでもアクセス可能
* protected => クラス内、同一パッケージ、サブクラスからアクセス可
* private => クラス内のみアクセス可能

制限無く公開したいなら public 。
基本的に外部からは隠蔽するが、サブクラスやパッケージ内からのみ利用させたい場合は protected 。
基本的に外部からは隠蔽し、クラス内からのみ利用させたい場合は private 。

という使い分けになっていて、かなり分かりやすく、使い分ける目的も明確です。

今回の話には関係ありませんが、アクセス修飾子を省略した場合には default というスコープもあります。

* default =>  クラス内、同一パッケージからアクセス可

## Ruby の private と protected

### るりまを確認

るりまでは下記のように説明されています。
http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fdef.html#limit

* public => public に設定されたメソッドは制限なしに呼び出せます。
* protected => protected に設定されたメソッドは、そのメソッドを持つオブジェクトが self であるコンテキスト(メソッド定義式や instance_eval )でのみ呼び出せ ます。
* private => private に設定されたメソッドは関数形式でしか呼び出せません。

※便宜上、るりまとは表記順を変えてあります。（スコープの範囲が広い順にした方が分かりやすいと思ったので）

説明だけだとピンと来ないかもしれないので、サンプルコードを提示します。

### private と protected の動作を確認

~~~ruby
require 'english'

class ScopeResearchClass
  def public_method
    'public'
  end

  def use_protected(other)
    puts other.protected_method
  end

  def use_private(other)
    other.private_method
  rescue
    puts $ERROR_INFO
  end

  def internal_use_private_and_protected
    puts protected_method
    puts private_method
  end

  def internal_use_private_and_protected_with_reciever
    puts self.protected_method
    self.private_method
  rescue
    puts $ERROR_INFO
  end

  protected

  def protected_method
    'protected'
  end

  private

  def private_method
    'private'
  end
end

pc1 = ScopeResearchClass.new
pc2 = ScopeResearchClass.new

begin
  pc1.protected_method
rescue
  # protected は外部からは呼び出せずにエラー
  puts $ERROR_INFO
end

begin
  pc1.private_method
rescue
  # private は外部からは呼び出せずにエラー
  puts $ERROR_INFO
end

# private / protected ともに内部から利用可能
pc1.internal_use_private_and_protected

# protected は レシーバーつきでも呼び出し可能
# private は レシーバーつきだと呼び出せず
pc1.internal_use_private_and_protected_with_reciever

class Hoge
  def can_not_use_external_protected_method(other)
    other.protected_method
  rescue
    puts $ERROR_INFO
  end
end

# 関係ないクラス内からは呼び出せないことを確認
Hoge.new.can_not_use_external_protected_method(pc2)

# protected メソッドは自クラスに別インスタンスを渡しても呼び出し可能
pc1.use_protected(pc2)

# private メソッドは自クラスに別インスタンスを渡した場合、レシーバーの指定が出来ないのでエラーになる
pc1.use_private(pc2)

class ChildProtectedClass < ScopeResearchClass
  def use_protected_from_child(other)
    puts other.protected_method
  end
end

# protected メソッドはサブクラスに別インスタンスを渡しても呼び出し可能
ChildProtectedClass.new.use_protected_from_child(pc2)
~~~

* 出力

~~~
protected method `protected_method' called for #<ScopeResearchClass:0x0000060044c770>
private method `private_method' called for #<ScopeResearchClass:0x0000060044c770>
protected
private
protected
private method `private_method' called for #<ScopeResearchClass:0x0000060044c770>
protected method `protected_method' called for #<ScopeResearchClass:0x0000060044c748>
protected
private method `private_method' called for #<ScopeResearchClass:0x0000060044c748>
protected
~~~

### protected を使うべき状況

protected を使うべき状況について、るりまにサンプルコードが掲載されていますが、
サンプルコードに少し補足をして、実行して動きを確認できるプログラムにしてみます。

~~~ruby
class Foo
  def _val
    @val
  end
  protected :_val

  def op(other)

    # other も Foo のインスタンスを想定
    # _val が private だと関数形式でしか呼べないため
    # このように利用できない

    self._val + other._val
  end
end

f1 = Foo.new
f1.instance_variable_set(:@val, 1) # => @val に無理やり 1 を設定
f2 = Foo.new
f2.instance_variable_set(:@val, 2) # => @val に無理やり 2 を設定
puts f1.op(f2) # => 3
~~~

## Ruby の private と protected の歴史

伊藤淳一さんの素晴らしいブログエントリに Ruby のパパ「 Matz 」さんとのやりとりが
まとまっています。
http://blog.jnito.com/entry/20120315/1331754912

* Matz さん曰く

~~~
Rubyのprivateの発想の元になったのはSmalltalkの「privateカテゴリ」です。
使わないでね、というだけでアクセスできちゃう。
Rubyはそれよりは若干強制力があります。
Rubyの反C++・親Smalltalkの設計思想が垣間見えますね

後でprotectedを追加したのもまずかった。
これでC++とキーワードが同じでも意味がズレてることになってしまったので。
~~~

## private と protected の使い分けに関する Matz さんの分かりやすい説明

Rubyのメーリングリストのやりとりより。
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/7669

* Matz さん曰く

~~~
つまり，privateは自分からしか見えないメソッドであるのに対し
て，protectedは一般の人からは見られたくないが，仲間(クラスが
同じオブジェクト)からは見えるメソッドです．

protectedは例えば2項演算子の実装にもう一方のオブジェクトの状
態を知る必要があるか調べる必要があるが，そのメソッドをpublic
にして，広く公開するのは避けたいというような時に使います．
~~~

### Ruby のメソッドの公開範囲の決定に関するマトリクス

|スコープ|全体に公開したい|外部から隠蔽したい|レシーバーを仲間が利用する|
|:--:|:--:|:--:|:--:|
|public|○|×|○|
|protected|×|○|○|
|private|×|○|×|

※仲間＝自クラスかサブクラスのレシーバー

## 参照
* るりまの クラス／メソッドの定義・呼び出し制限 の説明
    http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fdef.html#limit

* 伊藤淳一さんのブログより
    * JavaやC#の常識が通用しないRubyのprivateメソッド
        http://blog.jnito.com/entry/20120315/1331754912

    * Rubyのクラスメソッドは同じクラスのprotectedメソッドやprivateメソッドにアクセスできない
        http://blog.jnito.com/entry/20120504/1336080083

* Ruby のメーリングリストのやりとりより
    http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/7669

* るりまの Module クラスの public / protected / private の説明
    * http://docs.ruby-lang.org/ja/2.1.0/method/Module/i/private.html
    * http://docs.ruby-lang.org/ja/2.1.0/method/Module/i/protected.html
    * http://docs.ruby-lang.org/ja/2.1.0/method/Module/i/public.html