main,App,Applicationとか、冒頭からわかりにくいぞScalaさん。

なぜmainの記述方法が3つも用意されているのだ。「def main(args: Array[String])」の1行を省略させたいがためか、それをJavaとの比較で優位性を強調したいのか。Scalaの学習者は、冒頭から余計に悩まされることになる。


object Hi {
def main(args: Array[String]) = {
println("Hi! main")
}
}

object Hi extends Application {
println("Hi! Hi! Application")
}

object Hi extends App {
println("Hi! Hi! App")
}
上記の3つは、どれも似たような動作をする。Applicationの方は推奨ではないらしく、Appに書き換わる経過措置のようだ。

ScalaLispのようにコードとデータを区別する必要もない。Scalaでは言いすぎだが、Lispは正しくそうだ。Scalaの開発者はそれを意識しているのか、サンプルコードにソースコードを読み込んで処理させるものが目立つ。コードをread-evalして実行させたいのだ。Lispでは常套のことだった。上記のAppの実装もそれに近い。App内の実行ステートメントを保持して、mainの中でevalしている感じだ。


object Hi {
println("Hi! before")
def main(args: Array[String]) = {
println("Hi! main")
}
println("Hi! after")
}
と書くとコンパイルエラーにはならず、以下のように表示される。mainは最後に呼び出されていることが分かる。

Hi! before
Hi! after
Hi! main
では次にAppで試す。mainはoverrideしている。

object Hi extends App {
println("Hi! before")
override def main(args: Array[String]) = {
println("Hi! main")
}
println("Hi! after")
}
これだと以下のようにmainしか表示されない。

Hi! main
before、afterの実行ステートメントは実行されない。それを実行してくれるmainを書き換えているからだ。最後にApplicationで試す。mainは同様にoverrideしてみる。

object Hi extends Application {
println("Hi! before")
override def main(args: Array[String]) = {
println("Hi! main")
}
println("Hi! after")
}
これだと以下のようにbefore,after,mainの順に表示される。最初の通常のmainの記述と同じ結果だ。

Hi! before
Hi! after
Hi! main
この結果から、Appのみは、記述された実行ステートメントを保持して、mainの内部でevalしているようだ。必要ですか、Appが。そもそも、def mainの外に書いたprintln("Hi! before")やprintln("Hi! after")が実行されるというのは問題のない仕様なのだろうか。