JavaとしてもScalaとしてもコンパイルできるHelloWorld
タイトルの通り、以下のコードはJavaとしてもScalaとしてもコンパイルできます。
/*/**/ class JavaMain { public static void main(String args[]) { System.out.println("Hello, World"); } } // */ /*/**/ class App {} // */ /*/**/ class A { int object = 1; int ScalaMain = 1; void foo() { int i = // */ object /*/**/ ; i = // */ ScalaMain /*/**/ ; } class B // */ extends App { /*/**/ void bar() { // */ System.out.println("Hello, World"); /*/**/ } // */ } /*/**/ } // */
↑をPolyglot.java
, Polyglot.scala
として保存して試してみましょう。
$ javac Polyglot.java $ java JavaMain Hello, World $ rm -f *.class $ scalac Polyglot.scala $ scala ScalaMain Hello, World
わぁい動いた!
$ javac -version javac 1.8.0_77 $ scalac -version Scala compiler version 2.12.3 -- Copyright 2002-2017, LAMP/EPFL and Lightbend, Inc.
解説
ScalaとJavaにおける、ブロックコメントの挙動の違いがポイントです。
Scalaでは、ブロックコメントをネストさせた場合に/*
と*/
の対応をきちんと取りますが、Javaでは、何個/*
を開こうが、*/
が来た時点でブロックコメントが終了します。
Java:
/* -- (1) /* */ -- (1)が閉じる */ -- 余ってるのでsyntax error
/* -- (1) /* -- (2) */ -- (2) */ -- (1)
これを利用すると、javacにだけ認識されてscalacには無視されるコードを書くことができます。
いっぽう、scalacにだけ認識されるコードを書くのは難しいので、javacでコンパイルできるようにうまいこと色々足しています。
- L2..L6: javacだけに認識されるMainクラス
- L10: scala.Appを使ってScalaのMainクラスを作るので、javacで通るように空のAppを用意しておく
- L14..L39: javacで通るように色々挟みながら、
object ScalaMain extends App { System.out.println("Hello, World"); }
と書いている
まとめ
今回のコードはもちろんGroovyでもコンパイルできるので、Java, Scala, Groovy
のPolyglotができたことになります。
同じ感じでKotlinもいけるかな?