その「0」は何進数ですか？

~~*十進数だろ JK*~~

# はじめに

C/C++ で `0` と書くと八進数として解釈されるため、十進数のゼロを書くことはできないという小ネタがありますが、では他の言語ではどうだろうと気になりうっかり調べてしまったので記事にしました。
まあ八進数だろうが十進数だろうが処理系の気持の話でしかなく何かが変わるというものでもありませんが……

# 結果

## 概要
大まかに以下のグループに分けられました。

 - 八進数として解釈される
 - 十進数として解釈される (`0` 始まりの八進数リテラルもある) 
 - 十進数として解釈される (`0o` 始まりの八進数リテラルしかない) 
 - 十進数として解釈される (そもそも八進数リテラルがない)

この他、 `0` 始まりの八進数リテラルがあるものの `0` が八進数扱いなのか十進数扱いなのか調べても分からなかったものもありました。

## 結果一覧
 - *[2021-03-04 訂正: Go を `0o` 始まりの八進数しかないグループに分類していましたが、 `0` 始まりの八進数もあるとの指摘を受けて訂正しました]*
 - *[2021-03-04 訂正: JIS 規格には記述があるとの情報を受けて Ruby を不明から十進数に分類し直しました]*
### 八進数

 - C
 - C++

### 十進数 (`0` 始まりの八進数もある)

 - Go (`0` 始まりと `0o` 始まりの二種類の記法が可能)
 - Java
 - JavaScript (`0` 始まりと `0o` 始まりの二種類の記法が可能)
 - Ruby (`0` 始まりと `0o` 始まりの二種類の記法が可能)


### 十進数 (`0o` 始まりの八進数リテラルしかない)

 - Haskell
 - Python
 - Rust
 - Swift

### 十進数 (そもそも八進数リテラルがない)

 - C#
 - D
 - Kotlin
 - Scala

### 不明

 - Perl (開発中のバージョンでは [`0o` 始まりの表記も使える](https://perldoc.perl.org/5.33.5/perl5335delta#New-octal-syntax-0oddddd)ようです)

## 各言語の `0` の解釈の詳細

`0` 始まりの八進数が書ける言語についての `0` の解釈の詳細です。

### C

ISO/IEC 9899:2018 6.4.4.1 Integer constants の段落 1 より:

> *integer-constant*:
> 　　　　　　　　*decimal-constant* *integer-suffix*ₒₚₜ
> 　　　　　　　　*octal-constant* *integer-suffix*ₒₚₜ
> 　　　　　　　　*hexadecimal-constant* *integer-suffix*ₒₚₜ
>
> *decimal-constant*:
> 　　　　　　　　*nonzero-digit*
> 　　　　　　　　*decimal-constant* *digit*
>
> *octal-constant*:
> 　　　　　　　　`0`
> 　　　　　　　　*octal-constant* *octal-digit*
> ...

十進定数 (*decimal-constant*) はゼロ以外 (*nonzero-digit*) から始まるものと定義されているので `0` が十進数と解釈される余地がありません。
何より八進定数 (*octal-constant*) に燦然と輝く `0`。というわけで C では `0` は八進数。

### C++
ISO/IEC 14882:2020 5.13.2 Integer literals [lex.icon] より:

> *integer-literal* :
> 　　　　　　　　*binary-literal* *integer-suffix*ₒₚₜ
> 　　　　　　　　*octal-literal* *integer-suffix*ₒₚₜ
> 　　　　　　　　*decimal-literal* *integer-suffix*ₒₚₜ
> 　　　　　　　　*hexadecimal-literal* *integer-suffix*ₒₚₜ
>
> *binary-literal* :
> 　　　　　　　　`0b` *binary-digit*
> 　　　　　　　　`0B` *binary-digit*
> 　　　　　　　　*binary-literal* `’`ₒₚₜ *binary-digit*
>
> *octal-literal* :
> 　　　　　　　　`0`
> 　　　　　　　　*octal-literal* `’`ₒₚₜ *octal-digit*
>
> *decimal-literal* :
> 　　　　　　　　*nonzero-digit*
> 　　　　　　　　*decimal-literal* `’`ₒₚₜ *digit*
> ...

C と比べると *constant* という言い回しが *literal* になっていたり二進数表記や桁区切りもできるようになっていたりとやや違いはありますが `0` に注目してみると C と同じ。
十進数は `0` から始まることができず八進数に明示的に `0` があります。

### Go

The Go Programming Language Specification の [Integer literals](https://golang.org/ref/spec#Integer_literals) より:

> A single 0 is considered a decimal zero. 

と、 `0` は十進数と明記されています。形式的定義では

> ```
> int_lit        = decimal_lit | binary_lit | octal_lit | hex_lit .
> decimal_lit    = "0" | ( "1" … "9" ) [ [ "_" ] decimal_digits ] .
> binary_lit     = "0" ( "b" | "B" ) [ "_" ] binary_digits .
> octal_lit      = "0" [ "o" | "O" ] [ "_" ] octal_digits .
> hex_lit        = "0" ( "x" | "X" ) [ "_" ] hex_digits .
> ```

となっています。十進数リテラル (decimal_lit) に `0` が明示的に含まれ、八進数リテラル (octal_lit) には `0` の後に一桁以上必要です。

### Java

The Java® Language Specification Java SE 15 Edition の [3.10.1. Integer Literals](https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10.1) より:

> *DecimalNumeral*:
> 　`0`
> 　*NonZeroDigit* *[Digits]*
> 　*NonZeroDigit* *Underscores* *Digits*
> ...

と、十進数 (*DecimalNumeral*) に明示的に `0` が入っているので `0` は十進数です。
なお八進数の定義は

> *OctalNumeral*:
> 　`0` *OctalDigits*
> 　`0` *Underscores* *OctalDigits*
> ...

と、 `0` の後に一桁以上必要な定義になっています。

### JavaScript

ECMAScript® 2020 Language Specification の [11.8.3 Numeric Literals](https://262.ecma-international.org/11.0/#sec-literals-numeric-literals) より:

> *DecimalIntegerLiteral*::
> 　　`0`
> 　　*NonZeroDigit* *DecimalDigits*ₒₚₜ

なので Java と同様に `0` は十進数。
JavaScript の八進数は `0` 始まりと `0o` 始まりの二種類がありますが、 `0` 始まりの方の定義があるのは [B.1.1 Numeric Literals](https://262.ecma-international.org/11.0/#sec-additional-syntax-numeric-literals)。 strict mode では使えない記法。

> *LegacyOctalIntegerLiteral*::
> 　　`0` *OctalDigit*
> 　　*LegacyOctalIntegerLiteral* *OctalDigit*

ここも Java と同様、 `0` の後に一桁以上必要な定義。

### Ruby

[Ruby-Doc.org](https://ruby-doc.org) では見付けられなかったため、現行の Ruby より古いですが ISO/IEC 30170:2012 8.7.6.2 Numeric Literals より。`0` の扱いなんてそうそう変わりませんよね？

> *decimal-integer-literal* ::
> 　*unprefixed-decimal-integer-literal*
> | *prefixed-decimal-integer-literal*
>
> *unprefixed-decimal-integer-literal* ::
> 　`0`
> | *decimal-digit-except-zero* ( `_`? *decimal-digit* )∗
>
> prefixed-decimal-integer-literal ::
> 　`0` ( `d` | `D` ) *digit-decimal-part*
> ...
> *octal-integer-literal* ::
> 　`0` ( `_` | `o` | `O` )? *octal-digit* ( `_`? *octal-digit* )∗

`0d` 始まりの十進数というのもあるんですね。
それはさておき、 Java 等と同様に十進数の定義 (プレフィックスなし十進整数リテラル -- *unprefixed-decimal-integer-literal*) に明示的に `0` が入っており、八進数は先頭の `0` の他に一桁以上必要な定義になっています。


*(以下 Ruby を不明と分類していた時の内容)*
Ruby Syntax の [Numeric literals](https://ruby-doc.org/docs/ruby-doc-bundle/Manual/man-1.4/syntax.html#numeric) の例しか見付けることができませんでした。

> 123
> 　　integer
> -123
> 　　integer(signed)
> 1_234
> 　　integer(underscore within decimal numbers ignored)
> 123.45
> 　　floating point number
> 1.2e-3
> 　　floating point number
> 0xffff
> 　　hexadecimal integer
> 0b01011
> 　　binary integer
> 0377
> 　　octal integer
> ?a
> 　　ASCII code for character `a'(97)
>  ...

この記述からは `0` がどちらなのか不明。これまた気にしていない気もします。

### Perl

perlnumber の [SYNOPSIS](https://perldoc.perl.org/perlnumber#SYNOPSIS) の記述程度しか見付けることができませんでした。

> ```perl
> $n = 1234;              # decimal integer
> $n = 0b1110011;         # binary integer
> $n = 01234;             # octal integer
> $n = 0x1234;            # hexadecimal integer
> $n = 12.34e-56;         # exponential notation
> $n = "-12.34e56";       # number specified as a string
> $n = "1234";            # number specified as a string
> ```

これだけでは `0` が十進数なのか八進数なのか不明。そもそも `0` が十進数なのか八進数なのかという些細なことは気にしていないのかもしれません。


# おわりに

今回調べた範囲で `0` が八進数として解釈されるのは C と C++ のみで、他はすべて十進数扱いでした。C と C++ は何故異端っぷりを発揮しているのか……