Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiate case class with values to be set for its members

Consider this case class

case class sample(val s: String = { /*compiled code*/ })
{
  val name:String = { /*compiled code*/ }
  val no:Int = { /*compiled code*/ }
}

I need to create instance of this class with particular values set to name and no. But I cannot use another class which extends this class. I have to pass the same class instance.

like image 611
user2140033 Avatar asked Oct 21 '22 15:10

user2140033


2 Answers

You mean someone has gone to the trouble of making sure name and no are set a particular way and cannot be changed, and you want to make them contain something else, which may violate all sorts of assumptions? That's not a good idea, and the JVM will stop you from doing something so foolish (barring absurdly difficult tricks involving custom classloaders for everything).

If you merely mean that you want to set those vals, but not usually have to worry about them in the constructor, then there are a variety of solutions. One is to use lazy vals and private vars with setters:

case class C(val s: String = "fish") {
  private var myN: Option[Int] = None
  def initializeN(n0: Int) {
    myN = Some(n0)
    if (n != n0) throw new Exception("Already initialized")
  }
  lazy val n: Int = myN.getOrElse(s.length)   // s.length is your code block
}

Which works like so:

scala> C("salmon")
res0: C = C(salmon)

scala> res0.initializeN(2); res0.n
res1: Int = 2

scala> C("herring")
res1: C = C(herring)

scala> res1.n
res2: Int = 5

scala> res1.initializeN(2)
java.lang.Exception: Already initialized
    at C.initializeN(<console>:11)
        ...

There are various other tricks you can play if you want compile-time safety of initialization. Later parameter blocks can refer to earlier ones, and don't appear as match arguments:

case class D(val s: String = "fish")(val n: Int = s.length) {}

You can overload constructors:

case class E(val s: String, n: Int) {
  def this(s: String) = this(s, s.length)
  def this() = this("fish")
}

and various mixtures of the above are possible also.

like image 93
Rex Kerr Avatar answered Nov 15 '22 05:11

Rex Kerr


And making name and no constructor parameter is not an option?

case class Sample(s: String = { /*compiled code*/ },
                  name: String = { /*compiled code*/ },
                  no: Int = { /*compiled code*/ })

I assume that the /* compiled code */ determines the default values of the fields. You can use the code as follows:

Sample()                   // all default values
Sample("some value for s") // default values for name and no
Sample("s", "name", 123)   // explicit values, no defaults
like image 38
Malte Schwerhoff Avatar answered Nov 15 '22 05:11

Malte Schwerhoff