Say I have some case class in a library:
case class MyClass(a: Int, b: Int)
Later it turns out that there's a bug in my library and I need to apply some extra logic to one of these parameters to keep things working, so that from the user's perspective instances this can happen:
val x = MyClass(1, 2)
println(x.a) // prints '3' or whatever I happen to compute for 'a'
In other words, the final value for x.a is not necessarily what was passed in to the constructor. I know this looks crazy, but trust me, I need it. x.a will still return whatever was passed to the constructor in most cases, but there is one value for the constructor parameter that will lead to bugs and I need to transform it.
I see two ways to achieve this. I can make a a var:
case class MyClass(var a: Int, b: Int) {
a = someComputation()
}
but then the class becomes mutable because a can be set from the outside. My problem would be solved if I could remove or 'hide' the generated setter but it doesn't seem to be possible. If I add
private def a_=(newA: Int) {}
it doesn't override the setter generated by the var so it sees two method definitions and doesn't compile.
The second option is to create a field/method separate from the constructor parameter:
case class MyClass(private val _a: Int, b: Int) {
val a = someComputation(a)
}
but _a is used in all the special generated methods such as equals, toString, etc, whereas the custom field a doesn't feature.
Is there any way to transform the constructor parameters without affecting the rest of the API?
What I'd do, is override the apply method on the companion object to create an instance of MyClass with the right computation.
object MyClass {
def apply(a: Int, b: Int) = new MyClass(someComputation(a),b))
}
Then you can call it like val x = MyClass(1, 2), but you won't be able to call it like val x = new MyClass(1, 2) if you still want the computation to occur.
Instead I'd settle on another method on the companion object, it's not as nice a solution, but it should work:
object MyClass {
def create(a: Int, b: Int) = new MyClass(someComputation(a),b))
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With