Jas
Jas

Reputation: 15103

How can I access args from trait?

The following code:

trait TestMainArgs extends App {
  println(s"args are: $args") // I need to have a generic main in trait which refers to args...
}

object MyRealMainObj extends TestMainArgs {
  // I do not want to call the generic main from objects this would mean I would need to call them from every object which extendfs TestMainArgs
}

prints:

args are: null

While the following:

trait TestMainArgs extends App {
}

object MyRealMainObj extends TestMainArgs {
  println(s"args are: $args")
}

prints:

args are: [Ljava.lang.String;@f82f98

So how can I access args from the trait?

I want to put the logic of the "main" only in the super trait and I don't want code duplication like calling from every object which extends app the super main, is there any way to achieve that?

Upvotes: 2

Views: 142

Answers (2)

Justin Pihony
Justin Pihony

Reputation: 67075

Another option that is also deprecated is to override main:

trait TestMainArgs extends App {
  override def main(args: Array[String]) {
    println(s"args are: ${args(0)} from test")
    super.main(args)
  }
}

The problem is that the way traits are compiled, the constructor is triggered before the main object, which is where args is set. There appears to be no non-deprecated means to do this...

Upvotes: 3

childofsoong
childofsoong

Reputation: 1936

The answer lies in looking at both DelayedInit and App in the Scala source. The real gem lies in the doc comment at the start of DelayedInit:

Example:
 *  {{{
 *    trait Helper extends DelayedInit {
 *      def delayedInit(body: => Unit) = {
 *        println("dummy text, printed before initialization of C")
 *        body // evaluates the initialization code of C
 *      }
 *    }
 *
 *    class C extends Helper {
 *      println("this is the initialization code of C")
 *    }
 *
 *    object Test extends App {
 *      val c = new C
 *    }
 *  }}}
 *
 *  Should result in the following being printed:
 *  {{{
 *    dummy text, printed before initialization of C
 *    this is the initialization code of C
 *  }}}

So, just extend DelayedInit, follow the warnings you see in App (specifically, don't override args in your extending class), and you should be able to access them just as App does:

@deprecatedOverriding("main should not be overridden", "2.11.0")
def main(args: Array[String]) = {
  this._args = args
  //other stuff goes here as you like
}

However, if you do it like this, be aware that it is deprecated, like it says there, so you run the risk of losing the functionality in future versions of Scala.

Upvotes: 3

Related Questions