Help us understand the problem. What is going on with this article?

Rubyの8進数と2進数の構文エラー文の違い

最初に

Ruby その2 Advent Calendar 2020の16日目の記事です。
昨日は、 shxun6934さんの他言語の視点で見るRubyでした。
Part2の方はガラ空きなので、せっかくなので記事を投稿する。

なにか役立つような話ではなくて、Rubyの小話。
ただ、0o0始まりは8進数というのは、Rubyに限らずメジャーなプログラミング言語で多い仕様なので知らなかった方は知っておくといいことがありそう。
なお、最近の言語ほど、0o始まりのみ許して、0始まりは構文エラーにしている印象。

8進数と2進数のエラー文の話

前提として、2進数や8進数のリテラル

0b始まりの数値リテラルは、2進数として解釈し数値を作る。
0o0始まりの数値リテラルは、8進数として解釈し数値を作る。
0x始まりの数値リテラルは、16進数として解釈し数値を作る。

p 10   #=> 10
p 0b10 #=>  2
p 0o10 #=>  8
p 010  #=>  8
p 0x10 #=> 16

表にまとめると、次のような感じ。

prefix n進数 英語 その他
0b 2進数 binary
0o 8進数 octal 単なる0始まりは8進数
0d 10進数 decimal 19始まりは10進数
0x 16進数 hexadecimal

なお、prefixは大文字でも同じように動く。

8進数の構文エラー

8進数は、0~7の8つで構成される数だから、それ以外の8や9があると8進数として解釈できず構文エラーになる。
(※syntax errorと表示されずわかりにくいが、他のコードを前に書いても実行されておらず、確かに構文エラーである。)

p 0190
# Main.rb:1: Invalid octal digit
# p 0190
#   ^~~

Invalid octal digit(無効な8進数)と丁寧に教えてくれる。
しかし、これを2進数で同じようにやると、エラー文がよくわからなくなる。

2進数の構文エラー

2進数に0と1以外の数があれば、8進数と同じように
Invalid binary digitと表示されて欲しい。

p 0b12
# Main.rb:1: syntax error, unexpected integer literal, expecting end-of-input
# p 0b12
#      ^

試してみると、構文エラーになっているところまでは同じ。
しかし、unexpected integer literal(予期せぬ整数値リテラルだ)と怒られる。
よく見ると、エラー文の数値を指す位置も8進数のときと異なる。
8進数が指しているエラーの位置は、最初のprefixの0である。
対して、2進数が指しているエラーの位置は2である。
どうも8進数と異なり、2進数の場合は0b1までで2進数とちゃんと解釈された上で、
その数の真隣に別の整数値が来て構文が成り立たないというエラーらしい。

では、bの真隣に2という数を持ってきたらどうだろう。
0bでも0b2でも、2進数になりえない。さっきのエラー文とは違ってきそうである。

p 0b2
# Main.rb:1: numeric literal without digits
# p 0b2
#   ^~
# Main.rb:1: syntax error, unexpected integer literal, expecting end-of-input
# p 0b2
#     ^

0b2を別々に解釈して、前者0bnumeric literal without digits(数字のない数値リテラル)としてエラーをだして、前者と後者が不自然に連続していることに対して「(2は)予期せぬ数値リテラル」とエラー文をだしているようだ。

8進数は単純なエラーだったのに、2進数リテラルのエラー文はわかりにくい。

なぜ8進数のエラーは親切なのか

Ruby1.8を実行すると090で既に「Illegal octal digit」というエラー文がでる。
そして、1.9になると「Invalid octal digit」と今の言葉に変化した。
このあたりは昔から親切なエラー文だったようだ。

8進数と他の数値リテラルのエラー文の違いは何なのか。
自分なりに好意的に解釈して推測すると、以下の通りである。
8進数だけ英字なしの0始まりで数値を組める。
そして、電話番号や時刻に対して数値を使い10進数のつもりで0始まりの8進数リテラルで書いてしまうケースがあり、意図せずに8進数として使われたケースで誤りに気がつきやすいように8進数だけ親切にエラーを教えるようにしたのではないか。

しかし、2進数などのエラーはレアケースかもしれないが、それでもエラー文の内容はわかりにくいし頑張って紐解かないと分からないレベル。自分に直接的な害はないけど、気になってしまう。

最後に

8進数のエラー文は親切できっとググれば解決しやすい一方で、逆にいえば2進数などは何を言いたいかすぐにわかるレベルではないだろう。
まあ、人間の作っているものだし、こういう細かいところは手が届いていない感じがある。
理想ではこういう細かいレベルも何とかして欲しいなと感じるのもあり、記事にしてみた。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away