kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Kotlinの謎

Kotlinという言語の型システムは凄くおおざっぱに言ってしまうと、Scalaと非常によく似ています。

  • TopがAny
  • BottomがNothing
  • Byte, Short, Int, Float, ....といった、プリミティブ型相当の型が継承階層に組み込まれていて、型名まで同じ
  • Generics
  • Declaration-site variance
  • Use-site variance

違う部分、たとえばnullabilityを型システムレベルでサポートしてるとかはもちろんあるのですが、AnyとNothingという名前まで真似してる辺り、非常にScalaの影響が大きいのは間違いありません。

一方で、Kotlinがあえて採用しなかったものの一つに、暗黙の型変換があります。たとえば、Scalaでは、任意の型はUnitに暗黙に型変換できます。そのため、たとえば

val x: Unit = 1

というコードはコンパイル可能です。一方で、Kotlinは

val x: Unit = 1

というコードはコンパイルを通りません。これはまあ設計判断としてはどっちもありだと思います。

さて、それはいいのですが、一つ妙な点があります。次のプログラムを見てください:

gist.github.com

runは引数として渡された0引数無名関数を呼び出し、その最後の評価値を返すメソッドです。ここで、run<Unit> { 1 + 1 }とすることで、1 + 1の結果を強制的にUnitに変換しようとしています。普通に考えると、IntからUnit への暗黙の型変換が駄目なのだからコンパイルも通らなそうなのですが、何故かコンパイルを通ってしまいます。

これはKotlinが暗黙の型変換をサポートしていないという事実と反しているようにも思える。あるいは、実装のバグなのかもしれません。というわけで、Kotlinに詳しい方、何故これがコンパイルを通るか(どういうコードが生成されるかはわかっているので、仕様的に何故通るべきなのか)教えていただけないでしょうか(教えてクン)