Var recalculation after content change

I just started learning Kotlin and could not get one thing:

I have a variable that is based on some other variables (for example "A" and "B"). Is there an easy way to recalculate the resulted variable after i change var "A" or "B"? As i understood, i can just repeat the code for "result" again, but is there an easier way? i think in some cases the code could be quite long...

Example is below:

var valueA = 9
var valueB = 10
var result = valueA*valueB
println(result)

valueA = 15

"A" is changed, but if i write "println(result)" right now, var "result" will not be recalculated and will stay = 90

result = valueA*valueB
println(result)

only after i write the same code for "result" again, the output is recalculated

Upvotes: 4

Views: 201

Answers (3)

Ivan Wooll
Ivan Wooll

Reputation: 4332

You could always have a bit of fun with Delegates.observable() https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/observable.html

Example

var valueA by Delegates.observable(0) { _, _, _ ->
    calculateValueC()
}
var valueB by Delegates.observable(0) { _, _, _ ->
    calculateValueC()
}

var valueC: Int = 0

fun calculateValueC() {
    valueC = valueA + valueB
    println(valueC)
}

valueA = 5
valueB = 5

This would produce the output

5
10

Upvotes: 1

Sweeper
Sweeper

Reputation: 273988

If valueA and valueB are in a declaration scope, e.g. in a class/object declaration, you can declare a function or a property with a getter, and compute valueA * valueB, like in Ivo's answer.

If valueA and valueB are in a statement scope, e.g. in a function/lambda's scope (which they look like they are, judging by the fact that you are calling println right after), you cannot declare a property with a getter, but you can still declare functions.

If you don't like the () syntax when calling a function, I offer a third solution - property delegates. This works in both kinds of scopes.

First, make the function type () -> T a property delegate:

operator fun <T> (() -> T).getValue(thisRef: Any?, property: KProperty<*>): T = this()

Then declare result as:

val result by { valueA * valueB }
// then whenever you use "result", it will compute valueA * valueB!

Note that result becomes a val. You cannot change its definition as "valueA times valueB" after this.

Note that this could be breaking the principe of least astonishment. Some might be quite surprised by this.

You also might want to go for something like this instead:

val result by AutomaticComputation { valueA*valueB }

// ...

class AutomaticComputation<T>(val compute: () -> T) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = compute()
}

Upvotes: 2

Ivo
Ivo

Reputation: 23357

That's how variables work. When you store something in them it will be how you put it in at the moment. If you want a dynamic result use a function instead:

fun result() = valueA * valueB

and then print like

println(result())

If they are class variables (properties) you actually can use variables but then you need to define it with a getter like this for example:

val result get() = valueA * valueB

Upvotes: 5

Related Questions