Default arguments to Scala's main function? - scala

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)
}

Related

Import Scala object based on value of commandline argument

Lets say I have the following structure:
src
- main
- scala
- model
- One.scala
- Two.scala
- main
- Test.scala
where Test.scala extends App and takes in a parameter:
object Test extends App {
val param: String = args.head
// Based on param, I want to use either One or Two?
}
// sbt run Two
How do i use definitions in either One.scala or Two.scala depending on the runtime value of param.
Appreciate any/all inputs..
Make sure that One and Two share some common interface, choose the instance of this interface at runtime, then import the members of the instance:
trait CommonInterface {
def foo(): Unit
}
object One extends CommonInterface { def foo() = println("1") }
object Two extends CommonInterface { def foo() = println("2") }
object Main extends App {
// check args etc...
val ci = if (args(0) == "one") One else Two
import ci._
// do something with `foo` here
foo()
}

Scala fails to initialize a val

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...

Why can't I use this.getClass in auxiliary constructor in scala?

Why can't I use this.getClass in auxiliary constructor in scala? Are there any alternatives?
More specifically, I am trying to call LoggerFactory.getLogger of slf4j in the auxiliary constructor. I have an hack now where I am forced to pass a logger object to the constructor.
A simple contrived example (does not compile) which shows what I am trying to do:
class A (numbers : Double) {
val logger = LoggerFactory.getLogger(this.getClass)
def this(numbersAsStr: String) = this (try { s.toDouble) } catch { case _ => LoggerFactory.getLogger(this.getClass).error("Failed to convert"); 0 }
}
This is actually a limitation of the JVM rather than specifically a Scala problem. Here's a similar example in Java:
public class ThisTest {
public final String name;
public ThisTest(String n) {
name = n;
}
public ThisTest() {
// trying to use `this` in a call to the primary constructor
this(this.getClass().getName());
}
}
When you try to compile it you get an error:
$ javac ThisTest.java
ThisTest.java:10: error: cannot reference this before supertype constructor has been called
this(this.getClass().getName());
^
1 error
The problem is that you're trying to reference this before this any of the super-constructors for this have been called. You will have the restriction that you can't use a this reference in a super() or this() call no matter what JVM language you use, because that's the way classes work on the JVM.
However, you can totally avoid this problem by restructuring your code to put the reference to this after the this() call:
class A (numbers: Double) {
val logger = LoggerFactory.getLogger(this.getClass)
def this(numbersAsStr: String) = {
this ( try { numbersAsStr.toDouble } catch { case _ => 0 } )
LoggerFactory.getLogger(this.getClass).error("Failed to convert");
}
}
You might actually want access to the thrown exception for your log info. In that case, I'd just use LoggerFactory.getLogger(classOf[A]). That won't give you the actual class name if you're using inheritance (which I was assuming was the case here), but if you include the stack trace in the log then you should be able to figure it out.
Not sure I understand the question. Here is a guess:
class Foo(val c: Class[_]) {
def this() = this(classOf[Foo])
}
new Foo().c // -> class Foo

How to start the object

i need help with this code.
object test {
var list : Vector[MyType] = null
}
object foo extends MyType { // Mytype is a trait
println("TEST ")
test.list.:+(foo)
def myfunc() { //need to define this as this is there in the trait
// i do some operations
}
}
object Bar extends MyType { // Mytype is a trait
println("TEST ")
test.list.:+(Bar)
def myfunc(){
// i do some operations
}
}
now i want to go through the list and call myfunc() for all the objects that are extending MyType.
test.list foreach( t2 => t2.myfunc() )
the value's are not getting added to the list. Can someone let me know what i am doing wrong. Its not working. Is there a way to get that print statement working?
Your problem is, that the object is not constructed as a class, so that the code is called automatically. You could do two things. Either you extend App and call main or you write a function.
trait X
object test {
var list = Vector.empty[X]
}
object Foo extends App with X {
test.list :+= Foo
override def toString() = "Foo"
}
object Bar extends X {
def add() {
test.list :+= Bar
}
override def toString() = "Bar"
}
Foo.main(null)
Bar.add()
test.list foreach println
This code prints:
Foo
Bar
Extending App only adds a main methode to an object, containing all the code in the object.
You need to initialize test with an empty Vector rather than null. The way to do that in Scala is to use the factory method from the Vector object, and let type-inference do its job. For example:
var list = Vector.empty[MyType]
As you get the practice of doing that, you'll find yourself more focused on creating the data than on declaring its type, which in this case would have resolve this error before it happened.
Next the operation
test.list.:+(foo)
will not update test.list because, since Vector is immmutable, this method just returns a new updated copy and cannot affect the reference of list.
Try instead
test.list = test.list.:+(foo)
// or (with more idiomatic operator notation)
test.list = test.list :+ foo
// or (using syntactic sugar)
test.list :+= foo

Scala App val initialization in main method

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.