1

I often have a class with properties that are initialized at instantiation, like

class C { var x = 10 var y = v * 2 // v is some variable } val c = C() 

then properties of c are changed, and later I need to re-initialize the properties (so that c.x is 10 again and c.y is v*2, where the value of v may have changed).

My current approach is to initialize the properties with dummy values (or alternatively use lateinit and type annotations), and assign the desired values in an extra function ini like

class C { var x = 0 var y = 0 init { ini() } fun ini() { x = 10 y = v * 2 } } 

then I call c.ini() to re-initialize.

Is there a better (more succinct) way that avoids the dummy values?

Note that in JavaScript I can simply write

class C { constructor() { this.ini() } ini() { this.x = 10 this.y = v * 2 } } 
5
  • What do you mean by a "better" way? What's not good about this way? Do you not want to create a new instance of C? Commented Jan 15, 2022 at 15:20
  • I want to avoid the overhead of the dummy values, it's not a big deal, but I thought maybe there's a more succinct solution Commented Jan 15, 2022 at 15:24
  • There is no meaningful overhead for that. Don't worry about it. Commented Jan 15, 2022 at 15:33
  • I just thought of a more succinct way by abusing property delegates and reflection. That's probably overkill for this situation though. What you are doing is fine. Commented Jan 15, 2022 at 15:41
  • @Tenfour04 not in execution performance of course, just bloats the code if I have many such classes with a lot of such properties, but maybe you're right anyway Commented Jan 15, 2022 at 15:42

1 Answer 1

2

What you are doing right now is totally fine. I wouldn't change it.

If you want to avoid the placeholder values of 0, or if the type of the property has no placeholder value that make sense, you can store the initial values in private lambdas:

class C { private val xInit = { 10 } private val yInit = { v * 2 } var x = xInit() var y = yInit() fun reset() { x = xInit() y = yInit() } } 

If you really want to reduce the boilerplate, I can only think of this rather hacky and slow solution that relies on reflection. This could be usable if the instances don't need to be reset that often, and you have lots of these classes with resettable properties, and you just hate writing boilerplate reset methods.

class Resettable<T>(val supplier: () -> T) { var wrapped = supplier() operator fun getValue(thisRef: Any?, property: KProperty<*>): T { return wrapped } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { wrapped = value } fun reset() { wrapped = supplier() } } fun <T: Any> T.reset() { // look for properties delegated with Resettable this::class.memberProperties.mapNotNull { it.isAccessible = true (it as KProperty1<T, *>).getDelegate(this) }.filterIsInstance<Resettable<*>>().forEach { it.reset() } } 

Now you just need to do:

var v = 10 class C { var x by Resettable { 10 } var y by Resettable { v * 2 } } fun main() { val x = C() println(x.y) // 20 v = 20 x.reset() println(x.y) // 40 v = 40 x.reset() println(x.y) // 80 } 

Note that the first reset call would load all the kotlin reflection classes, and would take a noticeable amount of time.

Sign up to request clarification or add additional context in comments.

1 Comment

Sweeper, thanks for your extensive answer! Then I think I'll stay with my solution. I've added a comparison with JavaScript, I suppose boilerplate will be necessary in most or all statically typed languages?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.