概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: Ruby adds `Symbol#name` to return frozen string corresponding to the symbol name | Saeloun Blog
- 原文公開日: 2020/09/09
- 著者: Vamsi Pavan Mahesh
- サイト: Saeloun Blog
Ruby: Symbol#nameでシンボル名に対応するfrozen stringを返す(翻訳)
Ruby 3.0のSymbolクラスに#name
インスタンスメソッドが追加されました(#3514)。
このメソッドは、Symbolクラスのインスタンスである背後の値と同じStringクラスのインスタンスを返します。
:test.name
=> "test"
返される文字列はfrozenになります。
irb(main):002:0> :laptop.name
=> "laptop"
irb(main):003:0> :laptop.name.object_id
=> 180
irb(main):004:0> :laptop.name.object_id
=> 180
irb(main):005:0> :laptop.name.frozen?
=> true
上の例では、:laptop.name
の呼び出しが異なっていても同じobject_id
が返ります。つまり、”laptop”の最初のアロケーションの後でStringクラスの新しいインスタンスがアロケーションされないということです。
シンボルで#to_s
を呼んだ場合との違い
シンボルで#to_s
を呼んだ場合、戻り値の文字列はfrozenではありません。
したがって、Symbolの同じインスタンスで#to_s
を再度呼び出すと、Stringクラスの新しいインスタンスが作成されます。
irb(main):003:0> :laptop.to_s
=> "laptop"
irb(main):004:0> :laptop.to_s.object_id
=> 200
irb(main):005:0> :laptop.to_s.object_id
=> 220
上の例では、:laptop
で#to_s
を呼ぶたびにStringクラスの異なるインスタンスが生成されていることがわかります。
このメソッドの使いみちは?
シンボルで#to_s
を呼び出すコード片がアプリケーションのホットスポット(頻繁に実行される箇所)に存在していると、Stringクラスのインスタンスが大量に生成されて最終的にGC(ガベージコレクション)が行われる必要が生じ、GCによる負荷が増大します。
シンボルで#name
を呼べば、Stringクラスのfrozenインスタンスを得られます。
その後Symbolクラスの同じインスタンスで#name
を呼び出しても、先に得られたこのfrozen文字列が再利用されます。つまり、GCのオーバーヘッドが生じなくなります。
これまでの経緯
少し前のことですが、Symbolクラスで#to_s
を呼び出すとfrozenのStringインスタンスを返す提案が出されました(#16150)。
そしてRuby 2.7で提案どおりに実装されました(#2437)。
しかしその後、残念ながら後方互換性の問題が生じたために取り消さざるを得ませんでした(#16150のnote-45)
関連記事
Ruby: Symbol#to_sはRuby 2.7 previewでfrozen Stringを返したが今は違う(翻訳)