I have some code:
object Main extends App
{
val NameTemplate = """^([A-Za-z]+)_(\d+)\.png""".r
override def main (args:Array[String])
{
// Why is NameTemplate null here?
}
}
Why is NameTemplate not initialized within the main method?
If you are using App trait, then you don't need to override main method - just write your code in the body of the object:
object Main extends App {
val NameTemplate = """^([A-Za-z]+)_(\d+)\.png""".r
println(NameTemplate)
val NameTemplate(name, version) = args(0)
println(name + " v" + version)
}
It works because App trait extends DelayedInit trait which has very special initialization procedure. You can even access arguments with args, as shown in the example.
You still need to write main method if you don't want to extend App, but in this case it will work as expected:
object Main {
val NameTemplate = """^([A-Za-z]+)_(\d+)\.png""".r
def main(args: Array[String]) {
println(NameTemplate)
val NameTemplate(name, version) = args(0)
println(name + " v" + version)
}
}
The DelayedInit trait (which App extends) causes rewriting of intialisation code to execute within a special delayedInit() method. This would then normally be invoked by main. Since you are overriding main, however, the delayedInit() code is never being invoked, and as such your value is not being initialised.
As #tenshi explains, you can get around this either by not extending App or by moving your main code into the body of your Main object.
Related
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
Consider we have the following:
class Base { def name = "Base" }
class Successor extends Base {
override def name = "Successor"
}
I have tried to do the following (took from How to call a superclass method using Java reflection):
import java.lang.invoke.{MethodHandles, MethodHandle, MethodType}
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val h1 = MethodHandles.lookup().findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor]);
println(h1.invoke(a));
}
}
but I get a runtime exception:
java.lang.IllegalAccessException: no private access for invokespecial: class Successor, from TestApp$
I was told that it is possible that Java reflection may not work correctly for Scala. Is it true? Or I simply do something wrong?
Actually, you can NOT even do it in Java. Note, in the answer of "How to call a superclass method using Java reflection", it works because the Test extends the Base: public class Test extends Base {...}.
It looks like it is possible and Java reflection works for Scala as well, I just didn't read all answers for How to call a superclass method using Java reflection.
The following code works:
object TestApp {
def main(args: Array[String]) {
val a = new Successor;
val impl_lookup = classOf[MethodHandles.Lookup].getDeclaredField("IMPL_LOOKUP")
impl_lookup.setAccessible(true)
val lkp = impl_lookup.get(null).asInstanceOf[MethodHandles.Lookup];
val h1 = lkp.findSpecial(classOf[Base],
"name",
MethodType.methodType(classOf[String]),
classOf[Successor])
println(h1.invoke(a)) // prints "Base"
println(a.name) // prints "Successor"
}
}
Thanks to Jesse Glick for this solution.
I have found kind of a weirdness in the following Scala program (sorry to include all the code, but you'll see why I added it all) :
object md2html extends App {
private val DEFAULT_THEME = Themes.AMAZON_LIGHT
private val VALID_OPTIONS = Set("editorTheme", "logo", "style")
try {
// some code 1
} catch {
case t: Throwable => t.printStackTrace(); exitWithError(t.getMessage)
}
// some code 2 (method definitions only)
private def parseOption(key: String, value: String) = {
println(key + " " + VALID_OPTIONS)
if (! Set("theme","editorTheme", "logo", "style").contains(key)) exitWithError(s"$key is not a valid option")
if (key == "theme") Themes(value).toMap else Map(key.drop(2) -> value)
}
// some code 3 (method definitions only)
}
If VALID_OPTIONS is defined after one of the some code..., it is evaluated to null in parseOption. I can see no good reason for that. I truncated the code for clarity, but if some more code is required I'll be happy to add it.
EDIT : I looked a bit more into it, and here is what I found.
When extending App, the val is not initialized with this code
object Test extends App {
printTest()
def printTest = println(test)
val test = "test"
}
With a regular main method, it works fine :
object Test {
def main(args: Array[String]): Unit = {
printTest
}
def printTest = println(test)
val test = "test"
}
I had overseen that you use extends App. This is another pitfall in Scala, unfortunately:
object Foo extends App {
val bar = "bar"
}
Foo.bar // null!
Foo.main(Array())
Foo.bar // now initialized
The App trait defers the object's initialization to the invocation of the main method, so all the vals are null until the main method has been called.
In summary, the App trait and vals do not mix well. I have fallen into that trap many times. If you use App, avoid vals, if you have to use global state, use lazy vals instead.
Constructor bodies, and this goes for singleton objects as well, are evaluated strictly top to bottom. This is a common pitfall in Scala, unfortunately, as it becomes relevant where the vals are defined if they are referenced in other places of the constructor.
object Foo {
val rab = useBar // oops, involuntarily referring to uninitialized val
val bar = "bar"
def useBar: String = bar.reverse
}
Foo // NPE
Of course, in a better world, the Scala compiler would either disallow the above code, re-order the initialization, or at least warn you. But it doesn't...
How do I get this to work, I've tried with and without new keyword:
object Main extends App {
override def main (args : Array[String] = new Array("default argument")) {
println("args(0) = " + args(0))
}
}
http://ideone.com/5AyTxy (I have tried other [1, 2] methods but I think that its val is causing issues)
Docs: http://docs.scala-lang.org/sips/completed/named-and-default-arguments.html#default_arguments
PS: I should confirm that I want this to be bound to the args name; rather than to another var or val. Additionally the scope needs to be global within main.
Two notes:
1) When you extend App, the body of your object is your main function. "args" is a supplied value, you can just use it.
object MyApp extends App {
println(args)
}
2) main will always be called with arguments. This makes sense, since otherwise Scala (and Java) would be inconsistent. The JVM doesn't test to see if you have any arguments before passing the arg list to your main function. If it did, it would call main(Array("args")) sometimes, and main() other times, which would create a problem!
A better way to do this would be to actually use args as it is:
object MyApp extends App {
println(args.toList.headOption.getOrElse("Default first argument"))
}
If you want more than one argument though, you should check out a real argument parsing library, I recommend scopt.
To satisfy your intent here (as clarified by your last comment to #AlexIv's answer) - keeping the field name of args while allowing for a default value for the field - you can override the field, using a reference to the original value prefixed by super.:
object Main extends App {
override val args: Array[String] = if (super.args.isEmpty) Array("default argument") else super.args
println("args(0) = " + args(0))
}
You have to remove extends App and new:
object Main {
def main (args : Array[String] = Array("default argument")) {
println("args(0) = " + args(0))
}
}
But this won't help you cause main is an entry point to your application and default Array will be overwritten by the system, for example:
object Main {
def main (args : Array[String] = Array("default argument")) {
println(args.isEmpty)
}
}
Mac-mini:Desktop alex$ scalac main.scala
Mac-mini:Desktop alex$ scala Main
true
Mac-mini:Desktop alex$ scala Main hello
false
But if you need default Array, why not to make a new variable inside main?
object Main {
def main (args : Array[String] = Array("default argument")) {
val args = Array("default argument")
println(args.isEmpty)
}
}
or even shorter:
object Main extends App {
val args = Array("default argument")
println(args.isEmpty)
}
I have the following code. If I comment the call to "foo()" inside the actor's body, the code works fine. But if "foo()" is activated... my code freezes!
Anyone kwnows why?
import scala.actors.Actor._
object Main extends Application{
def foo() = {
println("I'm on foo")
}
def testActor() = {
val target = self
for(i <- 1 to 100){
actor{
foo()
target ! i
}
}
var total = 0
receive{
case x:Int => total += x
}
total
}
println("Result: " + testActor())
}
"testActor" is called while the "Main" class is initializing. The actor code is executing in a different thread(not the main thread) and it's blocked and can not send any message because it's trying to access a method in a class (Main in this case) that is being initialized in the main thread. "receive" hangs because it can not receive any message.
Do not use "extends Application". Use "def main(args: Array[String])" and save yourself a lot of trouble.
See http://scala-blogs.org/2008/07/application-trait-considered-harmful.html
The Application trait and its use is at fault here. When you have code running within the body of a Application rather than within a main method, that code is actually running as part of the constructor. So at the point where you call the testActor() method, the object hasn't actually finished initialising.
To fix it, move the println line into a main method:
def main (args: Array[String]) {
println("Result: " + testActor())
}
Because this problem happens so easily, the Application trait is considered to be bad news.