整数型に 'c' が代入できるそれぞれの事情

# これは何？

https://qiita.com/Cowsisland/items/71248bdd081089b7ba09

という記事で

```c:c
int a;
a = 'c';
```

が問題なく動いている話や [素晴らしいコメント](https://qiita.com/Cowsisland/items/71248bdd081089b7ba09#comment-732ca0b2d7c2a7be908d) があって面白かったので、記事にしてみた。

# それぞれの事情

## C言語

C 言語の場合、そもそも `'c'` の型が `int` である。
なので

```c:c
int a;
a = 'c';
```

は、わりと面白くない。

Twitter 方面で、 `'c'` の型が `int` であることに疑問を抱いている方が散見されるので追記。

なぜそうなっているのかは知らないんだけど、C 言語では古来よりシングルクオートで囲まれたリテラルは `int` 型になっている。規格書にもそう書いてある。

古い C でも

```c:c
printf( "sizeof('c') is %d\n", (int)sizeof('c'));
```

のようにすると「`sizeof('c') is 1`」ではなく「`sizeof('c') is 4`」など（4 じゃないかも）となることから、 `'c'` が `char` ではないことがわかる。`'c'` が `char` だと思いこんでいる方は是非試してほしい。なお、C++ では `'c'` は `char` なので、C++ としてコンパイルしないように注意が必要。

それはともかく。実際問題、`'c'` が `char` ではなく `int` だからといって `sizeof` に入れる以外の方法で違いがわかるパターンがないので、知っていても実用上嬉しいことは特に無い感じだった。C11 が出るまでは。
C11 で `_Generics` という新機能が入り、[`'c'` が int だと知らないと引っかかる罠が発生した](https://qiita.com/Nabetani/items/b37bc91ef2285f2f08d2) ので、注意が必要。

## C++ / C# / D / Java / Scala

C++ の場合、 `'c'` は `char` となっている。なので

```c++:c++
int a;
a = 'c';
```

とした場合、`char`  から `int` への暗黙の変換が発生する。この変換はほぼ必ず（`sizeof(int)==sizeof(char)` で、なおかつ `char` が `unsigned` の場合は安全ではないが、そんな処理系に触る機会がある人は稀だろう）安全なので、警告は出ない。

C# と D のことはよく知らないんだけど、同じように `char` のようなものから `int` のようなものへの暗黙の変換が起きるんじゃないかな（調べてない）。Java も同様かな（よく知らない）。

Scala の場合「弱い適合性」というルールに従って `Char` から `Int` への変換が許容されるらしい。わかってないけど。

## Go

Go は事情が違う。

```go:go
var a int
a = 'c'
```

とした場合。`a = 'c'` の右辺にある `'c'` は untyped rune。型は無いんだけど、強いて言えば `rune` みたいなことだと思う。
左辺の `a` は `int`。型なしから `int` への変換は、右辺の値が `int` の範囲内の値であれば成功する。

以下のように

```go:go
r := 'c'
var a int = r // cannot use r (type rune) as type int in assignment
```

untyped rune である `'c'` を型指定なしで変数に受けると、受けた変数は暗黙のうちに `rune` になる。`rune` から `int` への暗黙の変換はできないのでエラーになる。

## Groovy

Groovy の事情も面白い。

```groovy:groovy
Integer a
a = 'c'
printf("[%c]\n", a)
```

で `a = 'c'` で起こっていることはたぶん（自信ない）

1. `'c'` は文字列
1. 文字列を整数に代入しようとするので、暗黙の変換を試みる
1. 文字列の長さが 1文字の場合に限って、先頭の文字の文字コードを整数型の値として取得できる

ということだと思う。

```groovy:groovy
Integer a
s = 'c'
a = s
print("a=${a}/${a.class}  s=${s}/${s.class}") // a=99/class java.lang.Integer  s=c/class java.lang.String
```

のように、文字列から整数への変換ができる。また、 `s` の値を `''` や `'hoge'` などにするとエラーになる。

それと。
上記の例では `a` の型が確定するような書き方なので `a = 'c'` などとすると `'c'` を整数に変換する必要が出てくるが、`a` の型を宣言しないと

```groovy:groovy
a = 50
printf("${a} ${a.class}\n") // 50 class java.lang.Integer
a = 'c'
printf("${a} ${a.class}\n") // c class java.lang.String
```

このように、 `a` の型が変わる。

## zig

zig の事情は go と似ている。

```zig:zig
const stdout = @import("std").io.getStdOut().writer();

pub fn main() !void {
    var a: c_int = 'c';
    try stdout.print("a={}\n", .{a}); // a=99
}
```

`'c'` の型は `comptime_int` で、コンパイル時に値が確定しているけどビット長が確定していない整数型。
これを `c_int` に代入すると、値の範囲を検査して OK なら代入できる。
と、ここまでは go と同じ感じ。

go との違いは、情報欠落がない場合は暗黙の変換ができるという点。

```zig:zig
const stdout = @import("std").io.getStdOut().writer();

pub fn main() !void {
    var s: u8 = 'c';
    var a: c_int = s;
    try stdout.print("a={}\n", .{a}); // a=99
}
```

コンパイル時に値がわかっていれば

```zig:zig
const stdout = @import("std").io.getStdOut().writer();

pub fn main() !void {
    const s: i8 = 'c';
    var a: u32 = s; // 符号付きから符号なしへの変換
    try stdout.print("a={}\n", .{a}); // a=99
}
```

情報の欠落がありそうな変換でも暗黙の変換が普通にできる点は珍しいと思う。

さらに。 `comptime_int` に `u8` などの値を代入することもできるので

```zig:zig
const stdout = @import("std").io.getStdOut().writer();

pub fn main() !void {
    comptime var a: comptime_int = 1;
    comptime var z: u8 = 'z';
    try stdout.print("{}\n", .{a}); //=> 1
    a = 'c'; // 両辺 comptime_int
    try stdout.print("{}\n", .{a}); //=> 99
    a = z; // 左辺は comptime_int、右辺は u8
    try stdout.print("{}\n", .{a}); //=> 122
}
```

こういうパターンもある。この辺りも go の「型なし」とは大きく異る。

## Julia 

ほぼ使ったことがないのでよくわからない。仕様書も見たけどよくわからなかったので試したら。

```julia:julia1.6
a16::Int16 = 0
a32::Int32 = 0
a16 = 'c' # 'c' は 16bit の範囲内なので OK
a16 = '😀' # '😀' は U+1F600 なので 16bit の範囲外。エラー。
a32 = '😀' # U+1F600 も 32bit なら範囲内なので OK
```

どうも

* 'c' は実質的に整数型。
* `a = 'c'` のような代入があると、`a` が `'c'` を表現できるかどうかをチェックし、表現できれば代入可能。

っぽい。

# まとめ
整数型の変数 `a` に対して `a = 'c'` が合法である理由には各言語それぞれの事情がある。

上記をまとめると、推測も混じっているけどこんな感じ。

|言語|事情|
|:--|:--|
|C|`'c'` は `int` なので、両辺 `int`。|
|C++ / C# / D / Java / Scala|`'c'` は `int` ではないが、整数型。暗黙の変換で代入成立。|
|Go|`'c'` は untyped rune。異なる型への暗黙の変換はほぼ全部違法だが、untyped からの変換は、受け側の型が受け入れられる値ならOK。|
|Groovy|`'c'` は文字列。一文字の文字列の場合のみ、整数への変換が可能。|
|Zig|`'c'` は、`comptime_int`。`comptime_int` に限らず、コンパイル時に値がわかっている場合、受け側の型が受け入れられる値ならOK。|
|Julia|`'c'` はおそらく実質的に整数。代入先の整数型で表現できる場合には代入可能。たぶん。|