«前の日記(2010年06月15日) 最新 次の日記(2010年06月17日)» 編集

Matzにっき


2010年06月16日 [長年日記]

_ [Ruby] Ruby2.0の新機能(かもしれないもの)(2) nested def as local function

注意。このエントリはRuby 2.0に入るかもしれない機能について述べていますが、本機能が本当に2.0に採用されるかどうかは、未定です。

Rubyではメソッド定義のdefの中でdefを書くことができるが、 実際にはメソッド定義が遅延されるだけで、あまり役に立たない。

その理由については 原くんのHotlinkインタビューを見てもらうと良いと思う。

まつもと たとえばネストしたメソッドになにか意味をつけるとしたら、それは多分、そのスコープでだけ有効なメソッドを導入するっていうことだよね。

yhara 「ネストしたメソッド」になってしまうんですね。「ネストした関数」でなくて。

まつもと うん、まあ「ネストした関数」でもいいんだけど、でも Ruby にいま「関数」は無い。

yhara 無いですね。

まつもと だから、「関数」って言う新しいものを導入するって形になってしまう、のかな?

yhara 「ネストしたメソッド」っていうのは、なんか不自然な雰囲気がしますね。

まつもと メソッドの中で def を定義した時に何が定義されるかって言う時に、もしそれがメソッドであるとすれば、どっかのオブジェクトに属してないとダメだよね。で、そのスコープにいる時だけ存在するメソッドって何なんだろうって。

ささだ Argument オブジェクトとか作ってとかなんとか、ってなるかもしれませんね。

まつもと でもそれレシーバじゃないからね。「レシーバを省略すると self に行く」っていうルールと違うものを導入しないといけないことになるんだよね。

yhara すごく納得したのでもういいです。僕はもうその主張はしないことにします。

で、それに対するひとつのアイディアとして、「レシーバに対する特異メソッドを定義する」というものを考えていた。

最近思いついた、もうひとつ別のアイディアとして、「ネストしたメソッド定義は関数定義」にするというのもはどうだろうか、と考えた。

具体的には

def foo
   def bar(*args)
     ...
   end
   bar(1)
end

をコンパイル時に

def foo
   bar = ->(*args) do
     ...
   end
   bar.call(1)
end

と展開するというものだ。ローカル変数としてのbarにアクセスできるかどうかは未定だけど、 barは「関数」を引数なしで呼び出すことにするのか、lambdaが入っている リードオンリーの変数とするかどちらかだとと思う。

基本的にコンパイル時の問題なので、実装はさほど難しくないと思う。

ただし、問題(デメリット)もあって、十分な議論なしで安易に導入すべきではないとも思う。

  • ネストしたメソッドだけLisp-1的動作をするのは、モデルの統一性として問題ではないか。
  • ネストしたメソッドで定義された識別子をリードオンリーの変数とするならば、新しい変数種別を導入することになる。
  • 単体の識別子を引数なしの呼び出しとするならば、lambdaを取り出す手段がない
  • いずれにしてもコンテキストの情報が増えるので、bindingに手を入れなくてはいけない

やっぱ、導入は難しいかな。


«前の日記(2010年06月15日) 最新 次の日記(2010年06月17日)» 編集