Home > OS >  Kotlin is not able to change var using a method
Kotlin is not able to change var using a method

Time:10-31

Could someone explain why can't I change the value of var in that case ?

fun main(args: Array<String>) {
    var number = 3
    changeNumber(number)
}

fun changeNumber(number: Int) {
    number = 4 //here I see a warning "val cannot be reassigned"
}

CodePudding user response:

There is absolutely no way to do it directly. Kotlin copies a value for scalar types (Double, Float, Boolean, Int, etc.). So any internal changes are lost.

For others types Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.

So you can wrap up your number in for this example an IntegerHolder and change the value that is kept in the reference.

data class IntegerHolder( 
   var v:Int
)

fun main() {
  var a:IntegerHolder = IntegerHolder(2)
  changeNumber(a)// Echange a value
  print(a.v)
}

fun changeNumber(a:IntegerHolder) {
     a.v = 5      
}

CodePudding user response:

By passing a "number" to your function you "pass-by-value" NOT "pass-by-reference", the function does not know where in memory your main number is stored, therefore it cannot change it's value

you can see more about the subject here and here

CodePudding user response:

Just in case you find the other answers a bit confusing, I'll add that you don't need to know about what's a scalar or passed by value. Those are under-the-hood optimizations that the compiler does but don't change the logical behavior of your code.

Kotlin works only with references, not pointers. What you're trying to do is what you can do with pointers in a language like C or C . In those languages, you can pass a pointer to a function. A pointer is not the value of a variable, but the memory address of the variable itself so other functions can modify what the variable address is pointing at.

That's flat out not supported in Kotlin. You can only pass references. You are passing the object that the variable is pointing to, but you can't do anything to that variable itself. You are not passing a copy of that object, so if that object is mutable, you could change the values of properties inside it and the original function could see those changes by inspecting the object again. But many simple classes like Int, Float, Double, and String are all immutable, so it's logically irrelevant that you aren't passing a copy (and that's why Kotlin under-the-hood can optimize by passing actual values for some of these, called "inline classes").

A couple of workarounds for this limitation:

  1. Mutable wrapper class. Use this in as your variable type and function parameter type.
data class IntWrapper(var value: Int)

fun main(args: Array<String>) {
    val number = IntWrapper(3)
    changeNumber(number)
    println(number.value)
}

fun changeNumber(number: IntWrapper) {
    number.value = 4 
}
  1. Pass a function that can modify your variable. The setter function is the parameter for your function that changes the variable. (The difference between pointers and what we do here is that the function that changes the variable doesn't actually know that it's changing a variable. It's just calling the function that was passed to it, which could be doing anything it wants with the provided number.)
fun main(args: Array<String>) {
    var number = 3
    changeNumber { number = it }
    println(number)
}

fun changeNumber(numberSetter: (Int)->Unit) {
    numberSetter(4)
}

But it's not very often that you'll need to do one of these. It's more common to write functions that provide a return value, and you can use that value to reassign the variable. This strategy is more robust. It provides better encapsulation, which naturally makes your code less bug-prone.

fun main(args: Array<String>) {
    var number = 3
    number = produceNewNumber()
    println(number)
}

fun produceNewNumber(): Int {
    return 4
}
  • Related