Polymerase
Polymerase

Reputation: 6781

scala command skips running main if class outside of singleton object

EDIT: Main method is not called in Scala script is related (in particular, the answer from Régis Jean-Gilles). This post gives more details to describe the issue. And the answer (by suish) give a more practical demonstration to explain the behaviour of the scala command.

Content of MiniScalaApp.scala

object MiniScalaApp {
  def main(args: Array[String]) = {
    println(s"Scala Version: ${scala.util.Properties.scalaPropOrElse("version.number", "unknown")}")
    println(new Dinosaur("Tyrannotitan", 4900))
    println(new Dinosaur("Animantarx ", 300))
  }

  class Dinosaur (name:String, weightKG: Int) {
    override def toString = f"$name, Weight: $weightKG kg"
  }
}

Executed at the command line by:

$ scala /myProject/src/main/scala/MiniScalaApp.scala

Produces the expected output:

Scala Version: 2.11.7
Tyrannotitan, Weight: 4900 kg
Animantarx, Weight: 300 kg

However, if the Dinosaur class is placed outside of the singleton object MiniScalaApp then the scala command produces no console output, no error message.

object MiniScalaApp {
  def main(args: Array[String]) = {
    println(s"Scala Version: ${scala.util.Properties.scalaPropOrElse("version.number", "unknown")}")
    println(new Dinosaur("Tyrannotitan", 4900))
    println(new Dinosaur("Animantarx ", 300))
  }
}

class Dinosaur (name:String, weightKG: Int) {
  override def toString = f"$name, Weight: $weightKG kg"
}

In this 2nd version, to get the console output, the code must be compiled first and then run the MiniScalaApp.class separately

$ scalac /myProject/src/main/scala/MiniScalaApp.scala
$ scala MiniScalaApp

Question: What is the reason the scala command treats the code differently?

Upvotes: 4

Views: 161

Answers (2)

suish
suish

Reputation: 3343

scala -help explains all.

A file argument will be run as a scala script unless it contains only self-contained compilation units (classes and objects) and exactly one runnable main method. In that case the file will be compiled and the main method invoked. This provides a bridge between scripts and standard scala source.

so the latter case which is defining object and class, It will run the code as script. in another way to say, what It does is exactly the same as...

scala> :paste
// Entering paste mode (ctrl-D to finish)

object MiniScalaApp {
  def main(args: Array[String]) = {
    println(s"Scala Version: ${scala.util.Properties.scalaPropOrElse("version.number", "unknown")}")
    println(new Dinosaur("Tyrannotitan", 4900))
    println(new Dinosaur("Animantarx ", 300))
  }
}

class Dinosaur (name:String, weightKG: Int) {
  override def toString = f"$name, Weight: $weightKG kg"
}

// Exiting paste mode, now interpreting.

defined object MiniScalaApp
defined class Dinosaur

only defining.so you need to call it explicitly.

MiniScalaApp.main(Array())

In addition to that, object Foo extends App can't be used if the file have only one top-lebel object.def mainis required.

Upvotes: 1

ale64bit
ale64bit

Reputation: 6242

Seems like you need to invoke the main method explicitly if there is more than 1 top-level class/object:

object MiniScalaApp {
  def main(args: Array[String]) = {
    println(s"Scala Version: ${scala.util.Properties.scalaPropOrElse("version.number", "unknown")}")
    println(new Dinosaur("Tyrannotitan", 4900))
    println(new Dinosaur("Animantarx ", 300))
  }
}

class Dinosaur (name:String, weightKG: Int) {
  override def toString = f"$name, Weight: $weightKG kg"
}

MiniScalaApp.main(args);

See here: Main method is not called in Scala script

Upvotes: 0

Related Questions