From: TAKAHASHI Masayoshi Date: 2002-07-21T00:03:57+09:00 Subject: [ruby-dev:17741] Re: self in block 高橋征義です。 このメールの要旨は以下の通りです: * ブロック内のselfを、そのブロックつきメソッドを定義した コンテキストにするのは強力すぎるかも。 * ブロック内のselfがブロックのあるコンテキストで決まる事自体は 別に変ではないと思う。 関数については、関数型な思考ってあんまり得意じゃないんで、 正木さんの希望に沿うにはどうすればよいかはよく分かりません(_o_) 引用は前後します。 masaki wrote: > (情報隠蔽という言葉の使い方が間違っているかも知れませんが、素人の > 誤解だと思って御容赦ください) それでは、せっかくなので、ものの本の定義でも見てみましょう :-) 情報隠蔽は次のような原則である。 とくに公にすると宣言されていない限り、モジュールに関する 情報はすべてそのモジュールのみに属する非公開の情報である。 (Bertrand Meyer『オブジェクト指向入門』29ページ) # 石塚さんの『オブジェクト指向プログラミング』には # 「情報隠蔽」も「カプセル化」も索引にないんですけど、 # 石塚さんとしてはオブジェクト指向的にあんまり重要な # 概念じゃないんでしょうか? ;-) 「とくに公にすると宣言されていない限り」というところがポイント っぽいです。これを踏まえて、正木さんの例を見てみます。 > class C > def secret > p @secret > end > end > C.new.secret こちらの場合、クラスCに属するオブジェクトに対して、「secret」と いうアクセサ(reader)を用意しています。ので、「公にする」と 「宣言」していると考えていいでしょう。 > class C > def eval_yield > eval yield > end > end > > C.new.eval_yield { "p @secret" } こちらの場合は、evalを使っている時点で、ある種の「公開」を行って いる、と考えるのがよさそうです。 evalを使ってしまったために、外から与えたはずの文字列によって、 オブジェクト内に属する、つまり外には公開されていないはずの情報に がんがん触れることができるようになってしまう。これがevalの特長でも あり、またevalの危険性でもあります。だからこそ、あおきさんも 挙げていたinstance_evalにせよ、あるいはevalにせよ、Rubyでは濫用する べきでないとされている、と。 さて、正木さんの提案では、「<....>」を使ったブロックの中では、 selfをブロックを呼び出したコンテキストではなく、ブロックつきメソッド を定義したコンテキストにするべき、ということですよね。 これはつまり、ブロックにeval並みの強力さを必ず持たせるように する、ということに近そうです。 もちろん、そういう強力なブロック構文があっても駄目ではないで しょうが、そのように強力な構文の必要性と汎用性は疑問視せざるを えなさそうです。この「汎用性」というのは、単に使えるかどうか だけではなく、「強力すぎるので多用してはいけない」といった形 での抑制も含めた意味です。 もし、<....>を使ったブロックの構文を強力すぎるものにしてしまう なら、evalと同様あまり推奨されないものになってしまいそうです。 しかし、<....>を使ったブロック構文(と同等の、ブロック変数が ブロックローカルになるようにする構文)がRubyに欲しいと考えている 人たちは、それが積極的に使える・使われる構文であって欲しいと 思っているように見受けられます。であれば、このような「強力さ」は あまり望ましいものではないではないでしょうか。 > def method(...,&block) > ... self ... > end > この段階の情報で block 中の self が何を指すかを決めろと言われたら、 > method 中の self しか無いわけで、これが任意の object に成りうる > という現在の仕様の方が self のすりかえではないでしょうか? それはちょっと違うような。 class Foo def m(&block) yield end end class Bar def bar() foo = Foo.new() foo.m(){ p "self(in Bar#bar)=#{self}" } end end Bar.new().bar() #=> "self(in Bar#bar)=#" 上のスクリプトでは、Foo#m に渡したブロックの中のselfが、 FooのインスタンスではなくBarのインスタンスになっています。 これは、そのブロックの定義が Bar#bar のメソッド定義の一部 としてクラスBarの定義内に書かれている以上、いかにも情報が 「隠蔽」されているように思えますが、いかがでしょう。 高橋征義 (TAKAHASHI Masayoshi) E-mail: maki@rubycolor.org