Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Ruby: Symbol#nameでシンボル名に対応するfrozen stringを返す(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

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を返したが今は違う(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。