How can a function has mutable parameters?
It can’t. What are you trying to achieve?
This isn’t possible: in Kotlin, function/method parameters can’t be changed to point to different objects. (Though those objects can themselves be mutable, i.e. have their properties changed.)
In fact, early versions of Kotlin allowed parameters to be changed (like Java, C, and many other languages), but this was altered about 10 years ago. It was announced on the JetBrains blog, where they said:
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime). Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing in a function declaration (namely, it creates a property). Also, we all know that mutating parameters is not good style
(I’ve made a few trivial edits for grammar.)
See also this previous question, where JetBrains reiterated that policy (and most people agreed).
My own experience agrees with that: the rare cases where it would make sense to mutable parameters (e.g. to convert them to some canonical form or replace nulls) are easily handled by creating a local variable, but the subtle bugs and confusion that can result from making them mutable is much harder to work around.
Note that you can shadow function argument, which sort of mimic mutable function parameters:
fun foo(bar: Int) {
var bar = bar + 1
bar += 1
println(bar)
}
fun main() {
foo(1) // prints 3
}
Well, I would not recommend it, but it is possible.
The solution is very simple as you consider to pass reference types to functions.
1- create a generic wrapper like this
data class <T> Wrapper(var value: T)
2- embed values within it like this
val myInt = Wrapper(123)
val myStr = Wrapper("Hello World!")
3- define your param(s) function(s) taking specialised Wrapper type or not like this, and mutating Wrapped values
fun mutatingParamFunc(aInt: Wrapper<Int>, aStr: Wrapper<String>, aStuff: Wrapper<*>) {
aInt.value = 321
aStr.value = "Hello Earth!"
}
mutatingParamFunc(myInt, myStr, myStuff)
println(myInt.value)
println(myStr.value)
// >> 321
// >> Hello Earth!
I don’t buy the explanation for this one. It works elegantly in rust, and there is no appreciable runtime cost. Passing the entire state class (etc) just to mutate a single parameter in a function is semantically confusing, from the perspective of the function signature. And, the syntax for mutability is verbose and unwealdy.
Just let us pass an &mut reference in the function signature. Much easier to read and write; makes the function signature more general and reusable. This is because there’s no verbose creation and access syntax (e.g. MutableStateFlow creation and picking apart), and because the function would just take the variable it needs to use and mutate; not the whole wrapping class.
I will give lucoliver’s Wrapper syntax a try.
The JVM and Rust are two completely separate memory models. There is no way to pass things by reference on the JVM unless you do a memory allocation of a reference object.
You’re right; I don’t know enough about the implementation to trivialize that.
At the core of it, I am surprised (And frustrated) that I can’t write a function signature like this:
fun simpleOperation(val: &mut MyType) {
}
It is easy to use, easy to reason about, and general. And seems impossible in Kotlin.
This is very subjective. Technically speaking, there is no reason Kotlin couldn’t support this feature even if underlying JVM doesn’t. But for many people this feature is confusing, so Kotlin doesn’t support it.