Function parameters are "val" not "var"?

package testFunPass fun main(args : Array<String>){   println("in main")   test("a string")

}
fun test(in : String) {
  in = in + " here"
}

in is implicity declared as val according to the compiler in test()

How can I modify a parameter inside of the test function. I don’t want to modify them in the outter scope (unless I return it as a value) but I do want to change parameters inside of functions.
How do I pass them as var?

Thanks
Eric

2 Likes

package testFunPass

fun main(args : Array<String>){

  println(“in main”)

  test(“a string”)

}

fun test(x : String) {

  x = x + " here"

}

I realized I had used a keyword "in" but even with "x" the x is implied val

Eric

I believe this is a recent change. Parameters are now always val and cannot be modified. I believe the thinking is to reduce confusion, in case anyone things that the original passed value is changed.

2 Likes

It's a recent change indeed, details here: http://blog.jetbrains.com/kotlin/2013/02/kotlin-m5-1/

As of M5.1, all parameters are val and cannot be modified. If you want a mutable, you have to declare it explicitly in the body of the function.

Unfortunately, there’s no such thing as “passing parameters as var”. The only way of passing parameters on the JVM/JS is by value (when you pass an object reference the value of the reference is passed).
Theoretically, we could implement C#-liek out-parameters by boxing values, but this is costly and largely pointless. Use data classes to return multiple values from a function.

5 Likes

Thanks everyone.  I cut my teeth on FORTRAN in the late 60's and I guess I just think impertively and my native mode.

To take this to the next step, Objects passed into standalong functions are mutable and passed by ref.  I think that is good but I want to ask is that what is intended?


package testFunPass
class classy{
  public var a : Int = 1
}
fun main(args : Array<String>){
  var c = classy()
  println(“before test() ${c.a}”)
  test(c)
  println(“after test() ${c.a}”)
}
fun test(c : classy) {
  c.a = 2
  println(“inside test() ${c.a}”)
}

This is as it should be because you modify a member of the referenced object.

``

before test() 1
inside test() 2
after test() 2

This is intended.Only the reference itself is passed by value.

2 Likes

There is a difference between passing a variable by value versus reference, and with modifying a parameter within a function. The concept does not need to be so highly coupled.

Getting right to the point, I would have opted for default behavior to be immutable function parameters with an optional ability to re-assign the parameter/variable within the body of the function (not allowing or expecting the changed value to be seen by the caller). val (default) and var could have served that purpose.

The primary reasoning is that it is very common and shows greater clarity (my opinion) when a parameter also serves as a count-down variable in a very short function. Introducing an extra local variable in such cases reduces clarity.

Swift 2.2 had a similar feature to what I describe, but deprecated it in 3. But in their case, they also had an inout decoration as the source of the potential coding misunderstandings and therefore the rationale for deprecating re-assignment of parameters.

I too came over the same problem. The only break through is that the we need to pass the value of the arguments to the variables that’re declared inside the function, so that we can use them with other operations or apply operations on them.

I know this is an old thread. But perhaps there could be an annotation that marks primitive, non-optional parameters as being mutable in the function body?

It would be more precise to say that functions in Kotlin is pass by constant reference: only the shell of a class is immutable, and whether members is mutable depends on their modifier (val or var). With that being said, the work around here could be using a wrapper to bypass the constraint of val and access what you want to change within the wrapper.

ex:
// the member of val could be modified if it is var → make no sense to have var member
class WrapperToByPassVal (){
public var a1: Int = 1
}

fun testNestedClass(mutable: WrapperToByPassVal ) {
mutable.a1 = -1 ///<do your modification.
}

1 Like