RubyとStackサイズ
再帰段数は以下のコードで測りました。
puts "#{RUBY_PLATFORM} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" i = [0] def recursive(i) i[0] += 1 recursive(i) end begin recursive(i) rescue Exception => e p e puts "recursive size: #{i[0]}" end
結果
$ jruby1.0 recursive.rb java 1.8.5 (2007-05-31) #<SystemStackError: stack level too deep> recursive size: 934 $ ruby recursive.rb i486-linux 1.8.6 (2007-03-13) #<SystemStackError: stack level too deep> recursive size: 4109 $ ruby1.9 recursive.rb i486-linux 1.9.0 (2007-06-06) #<SystemStackError: stack level too deep> recursive size: 7265 $
どれもdebianパッケージのもので実行してますが、どれもサイズは少ないよなあ。ループだと10000なんて余裕で越すわけですし。
特に構文に仕込むRubyのメタプログラミングのようなことをした場合、このサイズが1/2にも1/3にもなりますから。現状はなかなか汎用の処理に対しては、Rubyメタプログラミングスタイルはとりにくかったりする。ただし、こういうタイプのコードの場合、結局は最後に(ユーザー定義の)ブロックを呼ぶ末尾呼び出しになりやすいから、このへんは末尾呼び出し対応してたらうれしいのになあ、というのが、pattern matchingを実装していて思ったこと。
もう一個:
puts "#{RUBY_PLATFORM} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" i = [0] class Recursive def initialize(i) i[0] += 1 Recursive.new(i) end end begin Recursive.new(i) rescue Exception => e p e puts "recursive size: #{i[0]}" end
結果
$ jruby1.0 recursive2.rb java 1.8.5 (2007-05-31) #<SystemStackError: stack level too deep> recursive size: 649 $ ruby recursive2.rb i486-linux 1.8.6 (2007-03-13) #<SystemStackError: stack level too deep> recursive size: 2824 $ ruby1.9 recursive2.rb i486-linux 1.9.0 (2007-06-06) #<SystemStackError: stack level too deep> recursive size: 2564 $
もう一個、Ruby式メタプログラミングで頻出のmethod_missingを使う場合
puts "#{RUBY_PLATFORM} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE})" i = [0] class Recursive def method_missing(name, i) i[0] += 1 self.call(i) end end begin Recursive.new.call(i) rescue Exception => e p e puts "recursive size: #{i[0]}" end
結果
$ jruby1.0 recursive3.rb java 1.8.5 (2007-05-31) #<SystemStackError: stack level too deep> recursive size: 774 $ ruby recursive3.rb i486-linux 1.8.6 (2007-03-13) #<SystemStackError: stack level too deep> recursive size: 3660 $ ruby1.9 recursive3.rb i486-linux 1.9.0 (2007-06-06) #<SystemStackError: stack level too deep> recursive size: 3632 $