From: TAKAHASHI Masayoshi Date: 2002-07-22T21:21:41+09:00 Subject: [ruby-dev:17763] Re: self in block 高橋征義です。 masaki さん: > 私は eval を利用して、実質的には希望している通りの block 構文 > を作って積極的に多用しています。 > 私にとっては、これが使えなかったら、Ruby を使う意味がないと思う位 > のものです。 むむ、そうですか。 eval系メソッドが好きで、これがなくっちゃ、という方もわりといるみたい ですよね。 # あおきさんやあづみさんがその口でしたっけ。 > 勿論、私にとって merit のほうが圧倒的に大きくても、他の人には > 致命的な demerit があるようだったら困るわけなので、 その望ましく > ないという具体例をあげてもらえないでしょうか? んー、何やら釈迦に説法的な物言いになってしまいそうですが、書いて みます。 問題になりそうなものとしてすぐに思いつくのは、あるオブジェクトの 値を操作する際に別の操作を行うようになっている場合、でしょうか。 class Foo ## 代入時にはログを吐かせる def param1=(val) @param1 = val write_log("@param1: #{val}\n") end ## 他の変数と同期させる必要がある def param2=(val) @param2 = val sync_some(@param2, @param2a) end ## サニタイジング(無毒化)する def param3=(val) @param3 = sanitise_some(val) end ## 上記の各変数とは関係のないはずの処理 def some_method(&block) yield(@param_x) end end このような場合、「ついうっかり」@param1や@param2や@param3を いじってしまった場合、予期せぬことが起きてしまうかもしれません。 例えば3番目の例で、CGIなどで入力時にサニタイジングするように していたのに、foo.some_method{ @param3 = "foo&bar"} といった サニタイジングされない代入が可能になってしまい、クロスサイト スクリプティング脆弱性ができてしまうかもしれません。 # いやまあ入力時にチェックするより出力時にサニタイジングする # のが基本だろ!と言われそうですが、それは言わない約束です。 そんな「うっかり」をする方が悪い、という話もありますが、そういう 「うっかり」をなくすための技法が、モジュール単位で情報を管理する というものだったはずです。上の例だと、 * Fooクラスを作る人は気をつける必要があるけれど、 * Fooクラスを使う人は気にしなくても安心、 という区別が期待されているわけですよね。その線引きが、{<....> .... } というブロックを導入することによって狂ってしまうわけです。 > "initialize に { ...} の形で与えられた block に対しては、 > その context を、initialize の中での context にする。 > $SAFE=1 のときにはこの機能は使えない。" > > initialize の段階では単に設定をするだけなので、まず危険なことは > なさそうだと思いますが如何でしょう。 うーん、なんだか「RCRシンドローム」っぽいように思えます。 http://www.ruby-talk.com/15226 なんとなくですが、「他の言語などで使える便利な機能をRubyに導入したい。 導入すればRubyがもっと便利になるだろう。それはRubyを少しいじれば導入 できそうだ。だからRubyを変更してみてはどうだろう」……という風に見え るのです。 しかし、その「少し」というのが曲者で、少しいじっただけでもRubyの デザインのバランスが崩れてしまうかもしれません。いっそのこと、少し だけいじって微妙な例外を増やすより、大きく変えた方がいいこともある でしょう。そもそも「便利な機能」そのものがRubyのデザインを歪ませて しまうことだってありえます。 というわけで、はやる心はおさえて、もうちょっと「Rubyの気持ち」に なって考えてあげた方が、しっくりくる解決法が見つけやすくなるん じゃないかと思います。 # 抽象的(というよりほとんど意味不明かも……)な言い方ですみません。 高橋征義 (TAKAHASHI Masayoshi) Email:maki@inac.co.jp