RubyKaigi Takeout 2020 の延長線で盛り上がってた Symbol#to_s について

RubyKaigi Takeout 2020 お疲れ様でした。
今回はオンラインということではじめて参加したんですが興味深い内容の話があって楽しかったです。
特に sawanobori からのサンダル紹介、焚き火で飯を炊いて魚を焼くコミッタの日常配信はニューノーマルを感じました。
いやー Ruby コミッタともなると過酷な環境で開発する技術が必要なんですねー勉強になります!
あ、あと Refinements はとてもすばらしく最高な機能なので皆さんどんどん使っていってニューノーマルになっていきましょう。

さてさて、まだまだ RubyKaigi 熱は冷めやらぬのですが今回は 1日目の Ruby Committers vs the World で盛り上がってた Symbol#to_s の話について簡単にまとめてみました。

Symbol#to_s で frozen String を返す提案

ちょうど去年の今頃 #to_s で返す文字列を frozen にしようという提案がされました。

このチケットで本題の『Symbol#to_s の戻り値 frozen にしよう』という話が出てきました。
また、このチケットでは Symbol#to_s だけではなくて以下のメソッドも frozen String を返す変更が含まれています。

  • Module#name
  • TrueClass/FalseClass#to_s
  • NilClass#to_s

関連する PR や経緯などは以下のリンクを参考にしてください。

この変更はまつもとさんから承認され、マージ後に Ruby 2.7 preview2 で『実験的な機能』としてプレリリースされました。

Ruby 2.7 で変わるはず『だった』 Symbol#to_s

Symbol#to_s が frozen String を返すようになってパフォーマンスが上がってよかったよかった。
で、終わればよかったんですが Symbol#to_s の変更をマージしたらいずれかの gem で問題があることがわかりました。
例えば pry では次のように Symbol#to_s の戻り値を破壊的に変更するコードが書かれていて影響が出ていました。

def method_missing(method, *args, &block)
  meth = method.to_s
  if meth.end_with?('?')
    # to_s の戻り値を破壊的に変更しているので frozen String だとエラーになる…
    meth.chop!
    present?(meth) || present?(meth.tr('_', '-'))
  else
    super
  end
end

このように Symbol#to_s の戻り値を破壊的に変更しているコードはいくつか報告され、また Ruby 2.7 ではキーワード引数周りの対応もあったので混乱を避けるために Ruby 2.7 では Symbol#to_s の対応は見送られることとなりました。
また、Revert されたのは Symbol#to_s の変更だけで以下のメソッドは frozen String を返すように変更され Ruby 2.7 の機能としてリリースされました。

  • Module#name
  • TrueClass/FalseClass#to_s
  • NilClass#to_s

1年の時を経て…

先月開催された RubyKaigi Takeout 2020Ruby Committers vs the World の延長戦でちょうど Symbol#to_s の議論がされていました。
そこでも Symbol#to_s をどうするのかいろいろと議論されていたんですが 1つの結論として Symbol#to_s を非互換にするのではなくて Symbol#name という別名のメソッドを追加する流れとなりました。
そしてその当日に Symbol#name が開発版へとマージされました。勢いある。

#16150 の時系列

まとめ

と、言う感じで Symbol#to_s 問題について簡単にまとめてみました。
結果だけ見れば影響範囲が大きい非互換だったんですが、実際にリリースしてみるまでわからない問題が存在するのはある程度は仕方ないのでむずかしいですねえ。
むしろ今回のケースではプレリリース版で問題があることがわかったのでプレリリースとしては正しい動きをしていた例とも言えますね。
正式版で問題になる前にわかってよかったよかった。
みなさんも Ruby 3.0 preview 版が出たらどんどん使ってみて問題がないか試してみましょう。

関連