🔠

Rubyに文字リテラル ?a が必要だった理由

2023/04/09に公開

最初に

自分自身、昔のRuby 1.8の時代にRubyを使っていたわけじゃなく、
題名自体、大げさだったりするかもしれないですが、ご容赦を。

コメントなど、気軽に書いてもらえれば、幸いです。

文字列リテラルではなく、文字リテラル?aとは。

そもそも、今は非推奨なポジションになることも多く、
文字リテラルを知らない人がいると思いますが、
文字リテラルとは「1文字専用の文字列リテラル」です。

p "abc" # => "abc" ...... 文字列リテラル
p ?a    # => "a"   ...... 文字リテラル

「るりま(Rubyリファレンスマニュアル)」にも記載があります。

文字リテラル
?の後に文字を1字指定した場合はその文字を表す文字列を返します。文字のエンコーディングはソースコードエンコーディングと同じに設定されます。

?a
文字 a を表す String

Ruby 1.8以前の?aは、数値リテラルだった

?aは、Ruby 1.9以降の現在は文字リテラルですが、昔は違いました。
Ruby 1.8以前は、文字コードを返す整数値リテラルでした。

# Ruby 1.8以前
p ?a    # => 97
p ?b    # => 98

るりまの1.8.7のリテラルの記載を見ても、
?aは数値リテラルに分類されていることがわかります。

数値リテラル

(中略)

?a
文字 a のコード (97)

どうして、1.8以前と1.9以降で挙動が違うのでしょうか。
続きます。

そもそも、1.8と1.9でRubyは大きく変わった

そもそも、Rubyで後方互換性がないぐらい破壊的に1番大きく変わったのは、1.8から1.9になる頃でした。
特に大きく変わったのが、文字列の扱いです。

例えば、文字列を[]で添字をとると、
今は文字(1文字の文字列)を返しますが、
1.8以前は文字コードの整数値を返していました。

# Ruby 1.9以降
s = "abc"
p s[0] # => "a"

# Ruby 1.8以前
s = "abc"
p s[0] # => 97

誤解を恐れずにいえば、Ruby 1.8以前はC言語みたいな仕様ですね。

【参考】

Ruby 1.8以前に ?a が使えると何が嬉しかったか?

String#[]が文字コードなる整数値を返すので、
(バイト単位での)n番目の文字が何であるか比較するとき等、
数値リテラル?aを使えると嬉しかったと思います。

# Ruby 1.8の時代では
str = "abc"
p str[0] # => 97

str[0] == 97 # true
str[0] == ?a # true

str[0] == 97と書くと意図がわかりにくいですが、
str[0] == ?aと書くと意図がわかりやすいし良いですよね。

だから、文字列まわりが大きく変わるので、?aも変わる必要があった

Ruby 1.8以前はstr[0] == ?aみたいなコードがあったはずです。
Ruby 1.9でstr[0]が文字を返すようになるにあたり
同じく?aも文字を返すようにすると、
str[0] == ?aが、1.8でも1.9でも同じように動いてくれるので嬉しいです。

まとめ

  • 1.8以前はstr[0]?aも文字コードなる整数値を返していた。
  • 1.9になるにあたり、str[0]?aも文字を返すようになった。

だから、まとめると、昔のRubyでn番目の文字str[n]を比較するときに?aのリテラルがあると嬉しかったし、1.9になるにあたり文字列まわりの仕様が大幅に変わるにあたり?aも今の文字リテラルに変わったって感じです。

今は?aはコードゴルフ等ではよく見られるでしょうが、
その他の場面では必要性もなく、避けられる現場も少なくないでしょう。

数年前、なんかのオンライン座談会のときに、
?aは必要ないから、文法的になくせ」ってMatz氏に言ってる方がいて、
Matzも今は不要だよねって感じのスタンスでした。
そのとき、他のあるRubyコミッターが、よく書くし便利で消されたら困ると反対していたのも印象的でした。

以上です。読んでいただき、ありがとうございました。

参考

Discussion