Edited at

ScalaはKotlinの親


はじめに

ここ数年で、Kotlinは急速な勢いで台頭してきており、Androidでは(おそらく)既に支配的な言語になっているかと思います。サーバーサイドKotlinはまだまだこれからというところがあるように感じますが、今後の発展次第でシェアを伸ばす可能性が高いでしょう。この記事では、そんなKotlinとScalaの関係について説明したいと思います。

結論からいうと、KotlinはScalaの直系の子孫であり、ScalaはKotlinの親であるといって差し支えないくらいKotlinがScalaから受けた影響は深いです。このことについて、私はパクリだとかそういうつもりは一切ありません(元々、プログラミング言語の発展というのは、色々な言語からアイデアを集めてきてこそですし)。しかし、最近、Kotlinについて、GroovyとScalaのいいとこどりであるとか(そのくらいにしか影響がないという意味)、better Javaとして一から作った(Scalaが与えた影響が知られていない)というような言説が増えてきたので、一人のScalaファンとして、Scalaが与えた影響がきちんとクレジットされることを願ってこの記事を書くことにしました。


歴史

Kotlinが初めてWeb上に登場した(当時はvapor-wareだった)のが、2011-2012年頃のことです。この時期は、Scalaがある程度の成功を見せた一方で、Scalaに対する不満も増えてきた時期であり、Red HatのCeylonとJetBrainsのKotlinという二つの言語が、ポストScalaを狙って開発され始めました(当時の記事を読むと、これらの言語の開発者がいかにScalaを意識していたかが伺えます)。そこで、CeylonはScalaとは全く違う方向の言語を作り始めましたが、一方で、KotlinはScalaの仕様をベースに言語を作ることにしたようです。このあたりは、Kotlinのリポジトリ の大昔のコミットをみると伺えます。コミットログを追う感じ、Scalaに似た構文をベースにして、構文を削ったり足したりと試行錯誤した様子がうかがえます。その間の細かい歴史は省きますが、2016年にKotlin 1.0がリリースされたのでした。


ScalaがKotlinに与えた影響

ここからが本題なのですが、ScalaがKotlinに与えた影響は実に多岐にわたります。これは、文法から型システム、はては起動スクリプト(シェル/バッチ)まで実に多くの面に及びます。


文法面での影響


変数宣言

ScalaとKotlinを触った人は知っていると思いますが、両方とも、変数宣言の時に

val x = 1 //不変

var y = 1 //可変

という形の文法を使います。また、型宣言を加えた場合も、

val x: Int = 1 //不変

var y: Int = 1 //可変

となり、ここの部分だけみると、ScalaとKotlinはほぼ全く同じ形の文法をしています。この、val/varという対の一致は偶然ではないでしょう(不変と可変の変数について違うキーワードを使うことはよくありますが、対のキーワード名まで一致していることはあまりないです)


クラスパラメータ

KotlinとScalaはともに、

class MyClass(x: Int, y: Int)

といった形でクラスを宣言します。ここで特筆すべきは、クラス名の後にコンストラクタ引数宣言が並ぶことで、これをクラスパラメータ(プライマリコンストラクタ)といいます。細かい点に違いはあるのですが、この部分の文法もやはりほぼ同じです(どちらでもコンパイル可能です)。また、クラスパラメータで宣言された引数のスコープはクラス宣言全体に及ぶ点も同じです(微妙な違いはありますが)。このクラスのインスタンスをnewするのにnewキーワードが要るか(Scala)、要らないか(Kotlin)という違いはあるものの、当時、このアイデアを採用していた言語である程度知られていたのはScalaくらいなので、Scalaから受け継いだのはほぼ間違いないでしょう。


if式

KotlinとScalaはともに、

if(cond) th else el

という形でif式を書くことができます。この辺りも、ほぼ全く形式の文法を持っています。


シングルトンオブジェクト

これは文法に関わる話でもあり、型システムに関わる話でもありますが、ScalaとKotlinの両方とも、

object Foo {

var foo1 = 1
val foo2 = 2
}

といった形でシングルトンオブジェクトを定義する文法を持っています。ともに、名前をつけたFooが値として扱えます。関数を定義するキーワードはdef(Scala)かfun(Kotlin)かで違いはありますが、それ以外はかなり類似しています。


case class/data class

Scalaのcase classは、

case class Person(name: String, age: Int)

のように定義すると、

val p1 = Person("foo", 1)     // Person("foo", 1)

val p2 = p1.copy(name= "bar") // Person("bar", 1)

といった形で、オブジェクトを簡単に生成でき、また、case classのクラスパラメータはフィールドとして公開されます。そして、case classとして宣言したオブジェクトは、==で比較できたり(equals()をオーバーライドしている)、Mapのキーになれる(hashCode()をオーバーライドしている)という特徴があります。Kotlinはそれに相当する文法として、data classを持っており、

data class Person(val name: String, val age: Int)

という形でクラスを定義でき、

val p1 = Person("foo", 1)       // Person("foo", 1)

val p2 = p1.copy(name = "bar") // Person("bar", 1)

という形で使えます。copyというメソッド名まで同一にしているのは興味深いです。また、case classと同様に、==で比較できますし、Mapのキーにもなれます。

とはいえ、複数の分岐を表現する構文がmatch(Scala)かwhen(Kotlin)かといった違いなどもあり、何から何まで同じ、というわけでもありません。ただ、ここまで見ただけでも、文法面での影響はかなり深いことが感じ取れたのではないかと思います。おそらく、KotlinとScalaの抽象構文を比較すると、かなり近い形になるのではと思います。


型システムに関する影響

型システムに関する影響はさらに顕著です。ScalaとKotlinとも、Javaの、Objectを頂点とする継承システムを持ったプログラミング言語であるとは言えるのですが、その中で、Scalaが先行して実装していた、IntByteShortといったプリミティブに相当する型を継承階層の中に位置づけてオブジェクトとして扱えるようにして、かつ、内部表現はJVMのプリミティブを扱うという手法をKotlinはそのまま踏襲しています(プリミティブ型に相当する型名は全て同じです)。

また、継承階層の一番上にある型(java.lang.Object)に相当する型は両方ともAnyで、継承階層の一番下にある型(これは、Javaには(明示的には)ありません)はNothingとなっていて、それぞれに役割も(nullに関すること以外は)同じです。AnyNothingという名前の対は、Scalaでも歴史的に色々変わってきているため、KotlinのそれはScalaのシステムをそのまま引き継いだと考えるのが妥当です。

さらに、宣言側の変性(declaration-site variance)という機能を両言語とも持っています。研究用言語としてはともかく、これを実用言語で持っているものは多くありません。Scalaの他にはC#などにもありますが、これはインタフェースにのみ変性の宣言ができるという制限がありますし、C#にはNothing相当型がないため、使い道も制限されます。この点、ScalaとKotlinの変性はキーワード(in/outか-/+)という違いがあるものの、同じです。

また、ScalaとKotlinには関数型(function type)があって、Scalaは

val f: Int => Int = (x) => x + 1

Kotlinは

val f: (Int) -> Int = {x -> x + 1}

という風に記述するのですが、ここで、関数型の引数の数が両方とも22個に制限されています(対応するクラスがFunction22までしかないため)。22という数字に特に意味はないので、この点でもKotlinはScalaの仕様を継承しています。


その他の影響

Kotlinの処理系には、kotlinc.batkotlinc というスクリプトがあるのですが、どちらにも

##############################################################################

# Copyright 2002-2011, LAMP/EPFL
# Copyright 2011-2015, JetBrains
#
# This is free software; see the distribution for copying conditions.
# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
##############################################################################

という記述があります。LAMP/EPFLというのは、Scalaの開発元のスイス連邦工科大学のMartin Odersky教授の研究室です。つまり、起動用シェルスクリプトはscalaの処理系からそのまま持ってきて(もちろん修正を加えて)いるのですね。


まとめ

この他にも、Kotlinのリポジトリの過去のコミットを見ると、Scalaを徹底的に研究した、というか、Scalaをベースにした色々改良をした節が見られる部分が多々あります。それはもちろん悪いことではなく(OSSですし、言語の進化のためにも悪いことではないと思います)、むしろ良いことだとも思います。

ただ、Kotlinという言語はScalaがあって初めて生まれたくらいに大きな影響を与えた、直系の子孫といってもいいくらいの言語である、ということは知ってもらえたら嬉しいです。

今後、KotlinとScalaのシェアがどうなるか色々わからないことがあるものの、後の技術に大きな影響を与えた先行技術がしっかりクレジットされないことは私は悲しいことだと思っているので、そのことが広まれば、と思います(繰り返しますが、パクリであるという意図はありません)。