← melang

暗黙の型変換

Last Updated: 2026-09-28 02:00

結論

melangでは、暗黙の型変換(暗黙的なキャスト)を一切許可しない。

型が異なる値を扱う場合、たとえ変換先に安全に収まることが保証できる場合でも、必ず明示的な型変換を記述する。int → longのような、値が壊れないことが分かりきった変換であっても例外を設けない。

int x = 10;
long y = x;          // NG
long y = x.toLong(); // OK

代入だけでなく、引数渡しや演算など、暗黙変換が発生し得るあらゆる場面で同じ方針を適用する。

long a = 10;
int b = 20;

a + b;          // NG
a + b.toLong(); // OK

melangが重視するのは、変換が安全かどうかだけではなく、「型を変換する」という処理そのものをコード上に明示することである。

冗長になることは許容する。簡潔さよりも、コードから型の変化を追跡できることを優先する。

なお、暗黙の型変換を禁止することと、型変換そのものを禁止することは別である。melangでは型変換自体は認めるが、必ずx.toLong()のような明示的なメソッドとして記述する。失敗し得る変換についてはtryToInt()のような命名とResult<T, E>を用いる(詳細は「型変換」のnoteで扱う)。

他言語比較

暗黙の型変換の有無は、言語によって大きく異なる。特にintからlongのような数値型間の変換は、言語ごとに扱いが分かれる。C系の言語は算術型の変換を広く暗黙に行う一方、Go・Rust・Kotlin・Swift・Zigのように数値型間の変換を一切暗黙に行わない言語も増えている。

言語暗黙の数値変換説明
Rustなし
MoonBitなし
Swiftなし
Kotlinなし
Javaあり(拡大のみ)
Scalaあり(拡大のみ)
C#あり(拡大のみ)
C++あり
Cあり(暗黙の整数昇格)
Goなし
Zigなし(comptime値のcoercionは別)
OCamlなし
F#なし
Haskellなし
Erlang一部あり(数値のみ)
Elixir一部あり(数値のみ)
TypeScriptなし(型検査上)
JavaScriptあり
PHPあり
Ruby一部あり(数値のみ)
Python一部あり(数値のみ)

比較の観点は次の通りである。

  1. 数値型間の暗黙変換があるか。
  2. 代入時と演算時で変換規則が異なるか。
  3. 情報を失う可能性のある変換(縮小変換)に明示指定が必要か。
  4. ユーザー定義型の暗黙変換を定義できるか。
  5. 型変換をメソッドとして表現するか、キャスト構文として表現するか。

C・C++・Java・C#・Scalaは、拡大変換(情報を失わない変換)を中心に暗黙変換を許容する。一方Kotlin・Swift・Go・Rust・MoonBit・Zigは、拡大変換であっても暗黙には行わず、変換メソッドやキャスト構文による明示を要求する。ただしZigは例外的に、リテラルのようなcomptime-known値(comptime_int/comptime_float型)に限り、収まる範囲であれば変換先の型へ自動的にcoerceされる仕組みを持つ。Python・Ruby・Elixirのような動的型付け言語は、数値の型階層内でのみ暗黙変換を行い、数値と文字列のような異なる種類の型は変換しない。JavaScript・PHPはさらに緩く、数値と文字列の間でも暗黙変換が働く。

トレードオフ

暗黙変換を許容する設計(C, C++, Java, C#, Scalaなど)

暗黙変換を許容しない設計(Rust, Kotlin, Swift, Go, MoonBit, Zigなど)

動的型付け言語の中間的な設計(Python, Ruby, Elixirなど)

以上を踏まえ、melangはKotlin・Swift・Go・Rust・MoonBit・Zigと同じ立場を取り、拡大変換を含むあらゆる数値型間の暗黙変換を禁止する。冗長さは許容し、予測可能性・安全性・明示性を優先する。