Why args are compulsory for main - scala

If I use like below considering I don't need to take arguments, it doesn't detect for Scala in eclipse.
object HelloWorld {
def main(): Unit = {
println("Hello Scala!!!")
}
}
It works fine with args: Array[String]
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello Scala!!!")
}
}

Well it's simply a convention on the JVM. You won't be able to invoke your object as entry point when running your program. For example, in Scala.js you have main() without arguments.
If you don't need the arguments you can mixin the App trait:
object HelloWorld extends App {
println("Hello Scala!!!")
}

Related

Why IntelliJ doesn't run my script if it has main in it

I am observing an interesting behavior. I have an existing project in which I created a folder and created a Scala script in that folder. To run it I did
Write a Scala script, e.g. MyScript.scala
In the menu select: Run -> Edit Configurations... Press the "+" (⌘N also works on the Mac in this dialog) Select "Scala Script" Then select your Script file in this dialog
Interestingly, if the script is the following then I get error Scala script not found
object HelloWorld{
def main(args:Array[String]): Unit ={
println("hello world");
}
}
but if the script is
def greetings(): Unit ={
println("hello")
}
greetings();
then it works!
Why IntelliJ cannot run the 1st version of the script?
You could do the following:
Run it as a script.
You have to use the following code:
class HelloWorld {
def main(args:Array[String]): Unit ={
println("hello world");
}
}
object Foo extends HelloWorld
Foo.main(args)
Hint: I removed the 'build' action from 'Before launch' to show the warnings further down.
Run it as an Application.
You can keep your code. Just select 'Application' when creating the configuration.
object HelloWorld{
def main(args:Array[String]): Unit ={
println("hello world");
}
}
Why?
You have to provide an entry point for the script. So you could use the following code:
object HelloWorld {
def main(args:Array[String]): Unit ={
println("hello world");
}
}
HelloWorld.main(args) //without this line, Script is not found!
But this gives an error (expected class or object definition):
An If you try to extend from App trait, you get 2 warnings:
object HelloWorld extends App {
override def main(args:Array[String]): Unit ={
println("hello world");
}
}
HelloWorld.main(args)
So I guess its best to use one of two Solutions above.

Override modifier is not allowed in Main however it is allowed when I extend App trait in scala

I am trying to create a Launcher program for my application and was going through the App trait and main method to decide which one to use. The only difference that I found between both is:
(1) Threaded code that references the object will block until static initialization is complete. However, because the entire execution of an object extending Application takes place during static initialization, concurrent code will always deadlock if it must synchronize with the enclosing object.
In my case I have a Launcher which basically initialize a Kafka loader object which keeps on running kafka poll. Below is my Launcher trait:
trait Launcher extends LazyLogging {
val config: Config
val actorSystem: ActorSystem
val sourceMessagesType = config.getString("app.source.dataType")
val targetTopic = config.getString("app.kafka.targetTopic")
val targetTopicPartitions =config.getInt("app.kafka.targetTopicPartitions")
val routingManager = HashedPartitionRoutingManager(targetTopic, targetTopicPartitions)
logger.info(s"Initializing MorpheusStreamDataLoader for $sourceMessagesType type")
sourceMessagesType.toLowerCase match {
case "json" => JSonDataLoader(config, routingManager)
case "avro" => AvroDataLoader(config, routingManager)
case _ => throw new IllegalArgumentException
s"Messages of type ${sourceMessagesType.toLowerCase} are not supported.\n"
}
}
Now to launch my application I was trying to find which is best to use, App or main method. However main method implementation doesn't work at all:
object ClientLauncher extends Launcher {
def main(args: Array[String]): Unit = {
override val config=ConfigFactory.load(args(0))
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
}
}
When I do this I get error on override modifier that override modifier is not allowed here. However if I use App trait it doesn't gives me any compile time error.
object ClientLauncher extends App with Launcher {
override val config=ConfigFactory.load(args(0))
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
}
The information that I got after reading couple of posts about App trait and main was that there is not difference other than the delayed initialization that happens when we use App trait. Why override doesn't works for main method and works for App? and what is the best way for me to launch my application?
You need to move them outside of the method so that they are object fields instead of local variables.
object ClientLauncher extends Launcher {
override val config=ConfigFactory.load()
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
def main(args: Array[String]): Unit = {
/*code*/
}
}
You won't be able to access command-line arguments or anything else local to main this way though.
If you need access to that and don't want to extend App, an alternative is to use a separate class to extend launcher.
class ClientLauncher(configFile: String) extends Launcher {
override val config=ConfigFactory.load(configFile)
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
}
object Main {
def main(args: Array[String]): Unit = {
new ClientLauncher(args(0))
}
}
Or to pass in those arguments as system properties instead of command line arguments.
object ClientLauncher extends Launcher {
override val config=ConfigFactory.load(sys.props("configFile"))
override val actorSystem: ActorSystem=ActorSystem("ClientActorSystem")
def main(args: Array[String]): Unit = {
/*code*/
}
}
and pass in the system property when you run your code
java -DconfigFile="config.conf" -jar myJar.jar

Using an object inside a class in same scala file

The following is the example that I am working on,
package com.sandbox.scala
class ScalaOne {
def main(args: Array[String]){
com.sandbox.scala.sayHello.hello(); //This works
sayHello.hello(); //error: not found: value sayHello
}
}
object sayHello{
def hello(){
println("Hello from Scala");
}
}
As you may see the second call sayHello.hello() throws an error mentioned in the comment. Why is that? I assumed it should work.

Code not running when main method is added

I',m following the akka tutorial from http://doc.akka.io/docs/akka/2.2.0/AkkaScala.pdf and below is the HelloWorld program. The main method is added by me but the I do not receive the "run as scala application" in Eclipse when I attempt to run it. According to the doc to run the program from the command line : "java -classpath akka.Main com.example.HelloWorld" but I require to run it from Eclipse so have added my own main method. Why will the below code not run ?
import akka.actor.Actor
import akka.actor.Props
class HelloWorld extends Actor {
override def preStart(): Unit = {
// create the greeter actor
val greeter = context.actorOf(Props[Greeter], "greeter")
// tell it to perform the greeting
greeter ! Greeter.Greet
}
def receive = {
// when the greeter is done, stop this actor and with it the application
case Greeter.Done => context.stop(self)
}
object Greeter {
def main(args: Array[String]) {
new HelloWorld
}
case object Greet
case object Done
}
class Greeter extends Actor {
def receive = {
case Greeter.Greet =>
println("Hello World!")
sender ! Greeter.Done
}
}
}
A main method has to be within a standalone object. Here you have it within an object within a class.

Compiling Scala scripts. How works a Scala script?

Groovy
Groovy comes with a compiler called groovyc. For each script, groovyc generates a class that extends groovy.lang.Script, which contains a main method so that Java can execute it. The name of the compiled class matches the name of the script being compiled.
For example, with this HelloWorld.groovy script:
println "Hello World"
That becomes something like this code:
class HelloWorld extends Script {
public static void main(String[] args) {
println "Hello World"
}
}
Scala
Scala comes with a compiler called scalac.
For example, with the same HelloWorld.scala script:
println("Hello World")
The code is not valid for scalac, because the compiler expected class or object definition, but works in the Scala REPL Interpreter. How is possible? Is it wrapped in a class before the execution?
The code in a Scala-Script is first placed in a Scala object, then compiled to JVM-Bytecode and at last executed. You can see the generated Scala object by writing scala -Xprint:parser my_file.scala:
package <empty> {
object Main extends scala.ScalaObject {
def <init>() = {
super.<init>();
()
};
def main(argv: Array[String]): scala.Unit = {
val args = argv;
{
final class $anon extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
println("hello world")
};
new $anon()
}
}
}
}
scalac will compile your code to java bytecode. println("Hello World") is not by itself a valid scala program, so scalac will not compile it.
You can do:
object Test extends App {
println("Hello World")
}
or
object Test {
def main(args: Array[String]) {
println("Hello World")
}
}
You can then run the output with scala Test.
Running the scala "interpreter" on a file that only contains the println("Hello World") line will basically wrap it in an object (transforming it into the first form we've seen above), compile it and run it for you under the hood.
Note that (even though the code looks very similar to a Hello World console application in java) the resulting compiled program is not the same thing that would result from the compilation of this java
/* note: this is Java code */
/* this does NOT compile to the same bytecode as the previous scala example*/
public class Test {
public static void main (String args[]) {
System.out.println ("Hello World");
}
}
Once you successfully compile a file with scalac, you can use javap, the java class file disassembler, to view the generated class and method signatures (Edit: thanks to #Luigi for pointing out that it is generated signatures, not code). That is, scalac HelloWorld.scala followed by javap HelloWorld.