GradleのプロジェクトでScalaを動かしてKotlinのコードを呼び出す

# 注意
正直この記事の内容に実用性はあまりないと思います。

# はじめに
この記事は [Scala Advent Calendar 2019](https://qiita.com/advent-calendar/2019/scala) 10日目の記事です。9日目は @cactaceae さん、11日目は @pictiny さんの [Scalaで日付の範囲を指定してリストを作る](https://qiita.com/pictiny/items/357630e48043185da223)です。

手元でちょっとしたプログラムを実行したいとき、REPLもいいですが、やはりIntelliJの強力な補完が使いたいということでPlayground的なプロジェクトをsbtで作ってそれをIntelliJ IDEAで開いてる人もいると思います。
自分もそういった感じで普段使っていたのですが、自分はScalaの他に普段Kotlinも書いていて、KotlinのほうはGradleでPlayground的なプロジェクトを用意していて、どうせならそちらでScalaも使えたほうが楽だよねということでやってみたことと、思いつきでKotlinのコードをScalaから呼び出してみたらできてしまったのでそれを記事にすることにしました。

サンプルを私のGitHubに公開しています。
https://github.com/yt8492/KotlinAndScalaPlayground

# 執筆時の環境
IntelliJ IDEA 2019.3 Ultimate Edition

# GradleプロジェクトにScalaを導入する
Gradleで適当に作ったKotlinのプロジェクトにScalaを導入していきます。

## build.gradle
pluginsブロックにidを追加します。

```gradle:build.gradle
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.61'
    id 'scala' // 追加
}
```

dependenciesブロックにScalaの依存を追加します。

```gradle:build.gradle
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
    implementation 'org.scala-lang:scala-library:2.12.6' // 追加
}
```

## Scalaディレクトリの追加
main直下のkotlinディレクトリなどがある階層と同じところにscalaディレクトリを作ります。
<img width="157" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270890/1848c779-1b27-41cb-5f35-449b86e33e39.png">

## 適当にコードを実行してみる
先程作ったディレクトリにファイルを追加します。

```scala:Main.scala
object Main {
  def main(args: Array[String]): Unit = {
    println("Hello Scala")
  }
}
```

この時点でIntelliJのRunが実行できますが、Gradleのタスクでのやり方も解説しておきます。

build.gradleのpluginsブロックにapplicationを追加し、MainClassNameを指定します。

```gradle:build.gradle
plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.61'
    id 'scala'
    id 'application' // 追加
}

mainClassName = "Main" // 追加
```

タスクを実行してみます。

```
./gradlew run
```

期待通りの結果が出力されると思います。

```
Hello Scala
```

# ScalaからKotlinのコードを呼び出す
適当にKotlinのコードを用意します。

```kotlin:Foo.kt
class Foo {
    fun bar() {
        println("bar")
    }
}
```

先程のScalaのコードを書き換えて呼び出してみます。

```scala:Main.scala
object Main {
  def main(args: Array[String]): Unit = {
    val foo = new Foo()
    foo.bar()
  }
}
```

このままでもIDEのRunから実行できますが、gradleのrunタスクで実行しようとすると以下のようなエラーメッセージが出て失敗するので、build.gradleを修正していきます。

```
projectPath/src/main/scala/Main.scala:3: not found: type Foo
    val foo = new Foo()
```

以下のブロックを追加するだけです。

```gradle:build.gradle
compileScala {
    classpath += files(compileKotlin.destinationDir)
}
```

これで

```
./gradlew run
```

でも実行できるようになったと思います。

## ScalaからKotlinがどのように見えているか
基本的にはJavaからKotlinを呼び出すときと同じです。

トップレベル関数は `ファイル名Kt.関数名` で呼び出します。

```kotlin:hoge.kt
fun hoge() {
    println("hoge")
}
```

```scala:Main.scala
 HogeKt.hoge()
```

ScalaとKotlinの両方にある機能であるデフォルト引数は、Kotlin側で `@JvmOverloads` をつけないと使えませんでした。やはりJavaから呼び出すときと同じようです。

```kotlin:Foo.kt
class Foo {
    @JvmOverloads
    fun baz(arg: String = "baz") {
        println(arg)
    }
}
```

```scala:Main.scala
val foo = new Foo()
foo.baz("bar") // bar
foo.baz() // baz
```

実行はできるのですが、IDE上でエラーが表示されていますね。
<img width="295" alt="スクリーンショット 2019-12-10 11.35.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/270890/fb6ea5fc-240a-1d1e-0dec-b49579719c54.png">

nullの扱いに関しては、やはりJavaからKotlinを呼び出すときと同じで、non-nullな引数にnullを渡すと実行時に落ちます。

```
Exception in thread "main" java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Foo.baz, parameter arg
	at Foo.baz(Foo.kt)
	at Main$.main(Main.scala:4)
	at Main.main(Main.scala)
```

# まとめ
- ScalaからKotlinを呼び出すことは、ScalaからJavaを呼び出すこととJavaからKotlinを呼び出すことと同じ
- IDEでエラーがでるあたり本来想定されている使われ方ではなさそう
- 実用性はあまりないと思われる