kiyoka.2014_02_12 RSSPLAIN

Related pages: !kiyoka.blog.list !kiyoka.blog.2014_02
55555555555555555555555555555555555555555555555555555555555554444443333333333345
5

[Ruby][Nendo] CRuby 2.1.0の非互換性-Symbolクラスにモンキーパッチできなくなった件

5
 iStock_000019986662XSmall
5

忘れないうちにNendoをCRuby 2.1.0で動かすのに苦労した話を書いておこう。

5

多分、SymbolにモンキーパッチしているプログラムはCRuby 2.1.0で動かなくなるので、その時に誰かの役に立つかもしれない。

5

 

5

CRuby 2.1.0に持ち込まれた非互換

5

 

5

.以下は、CRuby 2.0.0で動いて、CRuby 2.1.0で動かないコード

5
# Symbolへのモンキーパッチ
5
class Symbol
5
  def set_lineno(value)
5
    @lineno = value
5
  end
5
  def lineno
5
    return @lineno
5
  end
5
end
5
5
sym1 = :a
5
sym1.set_lineno( 10 )
5
p sym1.lineno
5
5
sym2 = :a
5
sym2.set_lineno( 20 )
5
p sym2.lineno
5

 

5
結果(ruby-2.0.0-p353)
5
$ ruby symbol.rb
5
10
5
20
5

 

5
結果(ruby-2.1.0)
5
$ ruby symbol.rb 
5
symbol.rb:5:in `set_lineno': can't modify frozen Symbol (RuntimeError)
5
        from symbol.rb:13:in `<main>'
5

 

5

何がしたかったのか

5

NendoはRubyで実装したScheme処理系(サブセット)である。

5

Nendo 0.6.6ではSchemeのソースコードをパースしたツリーの内部で、SchemeのシンボルはRubyのSymbol型に変換して保持していた。

5

そうするメリットは絶大で、Schemeの処理系の中で:quoteのようなRubyのSymbolと == 演算子で比較できる。

5

また、同時にそのシンボルがSchemeプログラムのソースコードのどの位置(ファイル名、行番号)に出現したかを保持したい。

5

つまり、同じSymbol型でも、位置情報を持っているものと持っていないものがあり、かつ、同じSymbol型として操作できる。

5

Ruby 2.0.0までは、乱暴だが上のようなモンキーパッチを使うことで、このトリックを実現していた。

5

 

5

Ruby 2.1.0

5

Ruby 2.1.0では上記のようなモンキーパッチは許されなくなった。

5

最適化のためか、はたまた安全性のためか、その両方かもしれないが、そのような挙動になった。

5

puppetも同様の問題でひっかかってpuppet側で対応したようだ。

5
 (maint) Fix can't modify frozen Symbol error on Ruby 2.1.0 by jeffmccune · Pull Request #2184 · puppetlabs/puppet · GitHubEXT
5

 

5

Nendo 0.6.8

5

Nendoも同様に0.6.8で地道に対応した。

5

Symbolへのモンキーパッチをやめて、ParsedSymbolという型を新規に作り、RubyのビルトインSymbolとの比較箇所などを地道に修正していった。

5

影響範囲は大きく、なかなか骨の折れる作業だった。

5

 

5

感想

5

本来はモンキーパッチは良くないコーディングだとわかっていたが、このような逃げを許してくれるのがRubyの良いところかと思っていた。

5

多分、モンキーパッチを許さないことで最適化しやすくなり実行効率は高まりそうな気がするので、CRubyの進化として良いことだろう。

5

ただ、ちょっと固くるしいなぁと思わなくもない。

5

言語が洗練するとはこういうことなのかなぁ。

5

 

4

追記 ( 2/23 )

4

SymbolもGCできるようにする改善だったようだ。それなら従おう。

4
 Feature #8906: Freeze Symbols - ruby-trunk - Ruby Issue Tracking SystemEXT
4
  Now, Integer and Float objects are frozen objects.
4
  How about to freeze Symbol objects, too?
4
  I think Symbol is friend of Integer.
3

...

3
  Background of this proposal:
3
  
3
  Now, I'm working on "GC-able Symbols" feature.
3
  Freezing symbols make this feature easier.
3
  
3
  for example:
3
  (1) set an instance variable @iv for symbol s
3
  (2) collect s
3
  (3) generate s
3
  (4) what value of @iv for s returns?
4

 

5

...comment disabled...