4
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-12-10

注意

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

はじめに

この記事は Scala Advent Calendar 2019 10日目の記事です。9日目は @cactaceae さん、11日目は @pictiny さんの Scalaで日付の範囲を指定してリストを作るです。

手元でちょっとしたプログラムを実行したいとき、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を追加します。

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

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

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

Scalaディレクトリの追加

main直下のkotlinディレクトリなどがある階層と同じところにscalaディレクトリを作ります。

適当にコードを実行してみる

先程作ったディレクトリにファイルを追加します。

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

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

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

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のコードを用意します。

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

先程の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()

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

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

これで

./gradlew run

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

ScalaからKotlinがどのように見えているか

基本的にはJavaからKotlinを呼び出すときと同じです。

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

hoge.kt
fun hoge() {
    println("hoge")
}
Main.scala
 HogeKt.hoge()

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

Foo.kt
class Foo {
    @JvmOverloads
    fun baz(arg: String = "baz") {
        println(arg)
    }
}
Main.scala
val foo = new Foo()
foo.baz("bar") // bar
foo.baz() // baz

実行はできるのですが、IDE上でエラーが表示されていますね。
スクリーンショット 2019-12-10 11.35.30.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でエラーがでるあたり本来想定されている使われ方ではなさそう
  • 実用性はあまりないと思われる
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1