C で定義されたメソッドと Ruby で定義されたメソッドで Continuation オブジェクトへの変数の保存のされ方が違う
callcc で遊んでいてローカル変数の保存のされ方ってどうなっているんだ?とふと思って試してみました。
試していたら、 C で実装されたメソッドと、Ruby で実装されたメソッドで変数の保存のされ方が違うことに気づきました。
cont = nil 10.times do |i| puts i if i == 3 callcc {|c| cont = c} end if i == 6 cont.call end end
これは
0123456456456456456456456456456456456...
と無限ループになります。 Integer#times の内部変数の値が復帰されていますね。
そして、Integer#times を以下の Ruby 版に差し替えて実行してみます。
class Integer def times i = 0 while i < self yield i i += 1 end self end end
すると
0123456789
という実行結果になります。
Ruby で実装された Integer#times のローカル変数 i の値が復帰していません。ローカル変数の‘値’は保存されていなくて、変数テーブルへの参照が保存されているようです。
Ruby で実装されたメソッドで C で実装されたメソッドでこんな違いが出てくるとは。C で定義されたメソッドのローカル変数については C のスタックとレジスタをコピーしてローカル変数の‘値’を保存するしかないから仕方ないということでしょうか。