user79074
user79074

Reputation: 5300

How to change a base class attribute of a case class

Take the following code:

class A(val i: Int)

case class B(str: String) extends A(1)

val b = B("test")

In my scenario I am restricted by the definition of B which cannot be changed. I also wish to avoid reconstructing B as I have many such objects with a lot more attributes than in this example.

Is there any way I can create a new copy of b (using reflection or otherwise) with a new value for i?

Something that would be the equivalent of:

val b2 = b.copy(i = 2)

NOTE: The question is can it be done? Not what the best programming practice is.

Upvotes: 0

Views: 96

Answers (3)

Dima
Dima

Reputation: 40510

You can do it using reflection with something like this:

  val b = B("foo")
  val c = b.copy()
  println(b.i) // prints 1
  val field = classOf[A].getDeclaredFields.head
  field.setAccessible(true)
  field.setInt(c, 2)
  println(c.i) // prints 2

But beware, this is not just "bad programming practice", but rather complete breakage of the contract.

Your declaration case class B(s: Sting) extends A(1) promises that all instances of B will always have i equal to 1, which is a lie.

Not to mention, fun facts like b == c being true or c.copy.i being 1 etc. Don't do this.

Upvotes: 1

Tim
Tim

Reputation: 27421

You can do this:

val b2 = new B(b.str) { override val i = 2 }

The downside is that you have to re-construct B from the parameters which may be cumbersome if there are a lot of them.

Upvotes: 0

SergGr
SergGr

Reputation: 23788

Not if you define B that way. But this code works for me:

class A(val i: Int)

case class B(str: String, override val i:Int=1) extends A(i)

val b = B("test")
val b2 = b.copy(i = 2)  

P.S. well technically you can just copy with no modifications and then edit i using reflection but this is not a great idea IMHO.

Upvotes: 0

Related Questions