Home > Back-end >  How to declare static global values and define them later in Scala?
How to declare static global values and define them later in Scala?

Time:01-27

Primary goal

I want to use some static vals in a class so that I don't have to pass them as function parameters.

My approach

Since I want them to be static, I am declaring them in the companion object. But I cannot assign them values when I declare them, for some reasons. So I am following the below approach.

case class DemoParams(name: String)

class Demo {
  def foo = {
    println("Demo params name is: ", Demo.demoParams.name) // Works fine
    anotherFoo(Demo.demoParams.name)           // Throws NPE !
  }
  def anotherFoo(someName: String) = {
    // some code
  }
}

object Demo {
  var demoParams: DemoParams = _      // Declare here
  def apply() = new Demo()

  def run = {
    demoParams = DemoParams(name = "Salmon")      // Define here
    val demoObj = Demo()
    demoObj.foo
  }

  def main() = {
    run
  }
}

Demo.main()

I am able to print Demo.demoParams but surprisingly, this throws a NullPointerException when I pass Demo.demoParams to another function, while running the Spark app on a cluster.

Questions

  1. Firstly, is this the right way of declaring static values and defining them later? I would prefer to not use vars and use immutable vals. Is there a better alternative?
  2. Second, could you think of any reason I would be getting a NPE while passing Demo.demoParams.name to another function?

CodePudding user response:

Your code works fine and doesn't throw anything (after fixing a few compile errors).

But ... Don't do this, it's ... yucky :/

How about passing params to the class as ... well ... params instead?

case class Demo(params: DemoParams) {
  def foo() = {
    println("Demo params name is: "   params.name) 
  }
}

object Demo {
  def run() = {
    val demoParams = DemoParams(name = "Salmon") 
    val demoObj = Demo(demoParams)
    demoObj.foo()
  }
}

CodePudding user response:

Not sure this is the best alternative, but consider using a trait, which still keeps you in the FP zone by avoiding the use of var:

case class DemoParams(name: String)

trait Demo {
  val demoParams: DemoParams
}

Then just define it where you need it, and it's ready for use:

object MainApp extends App {
  val demoObj = new Demo {
    override val demoParams: DemoParams = DemoParams(name = "Salmon")
  }

  println("Demo params name is: ", demoObj.demoParams.name) // (Demo params name is: ,Salmon)
  anotherFoo(demoObj.demoParams.name) // Salmon

  def anotherFoo(name: String): Unit = println(name)
}

About the second question, without the actual code one can only guess (this sample code does not throw NPE). Probably somewhere you are using it without defining it previously, because var demoParams: DemoParams = _ just initializes demoParams to the default value of the reference type DemoParams, which is null in this case, and you get NPE when you try to access the name value of a null object. This is why using var is discouraged.

  • Related