11

I am trying to create a swap function which takes in two parameters as shown below:

fun swap(a :Int, b:Int) {

}

I call it like this:

  var a = 10
    var b = 5

    swap(a,b)

    // a should be 5
    // b should be 10

The problem is that even if I swap the values inside the swap function it won't be reflected on the caller's side because it is passed as a copy and not as a reference.

Is there anyway to pass value types to swap function and allow the function the ability to change them.

john doe
  • 9,220
  • 23
  • 91
  • 167
  • 1
    Unless you wrap it in a object that holds the reference you can't do it. Such: class IntegerHolder { int value; } the reference inside the class can be changed in the method – Marcos Vasconcelos Aug 01 '18 at 17:17
  • By default the values passed to the swap function are "val". Is there anyway to change that to var? – john doe Aug 01 '18 at 17:20
  • 4
    Even if this was possible (as it is in Java), this doesn't give you pass by reference. Kotlin, just like Java, has no support for pass by reference on primitive types. – yole Aug 01 '18 at 17:25
  • 1
    Exactly, parameter pass are always by value and not by reference, they are no pointers you can swap – Marcos Vasconcelos Aug 01 '18 at 17:32
  • [This](https://discuss.kotlinlang.org/t/pass-by-ref-for-inline-functions/4805/22?u=reitzig.1) may be helpful. – Raphael Oct 22 '18 at 17:36

4 Answers4

6

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 any other type, Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.

There is no way to change this behaviour.

After trying many ways to overcome the impossibility of passing scalar by reference, as happens in Kotlin, Java and some other languages; my current strategy is using for any scalar type a plain and generic wrap, as an above comment suggest.

Recently, I'm using this trick for everything, including inside a function that otherwise would demand that I return multiple values. The alternative is joining the returns in a artificial class or destructuring declarations: val (a, b, c) = function-call() syntax. However, I hate articial classes and destructuring declaration is for local variables only, and it's annoying when some needs visibility out of current block of commands.

My code is very simple:

data class p<T>(   // It's a generic wrap class for scalar type T
   var v:T
)

fun <T>swap(a:p<T>, b:p<T>){  // It's a generic swap for scalar types
  var aux:p<T> = a.copy()
  a.v = b.v
  b.v =aux.v 
}


fun main() {
  var a:p<Int> = p<Int>(2)   // 'a' is a kind of 'Int' variable
  var b:p<Int> = p<Int>(3)   // and so is 'b'
  swap(a,b)  // Exchange 'a' and 'b' values
  println(a.v)  // 3
  println(b.v)  // 2
}

The only drawback is not being able to use syntax sugar of a real scalar type.
I am forced to add .v on any use of a scalar variable.

I only uses that for variables that I need pass by reference in some function and it's not so common. I try, when possible, avoid collateral effects.

Paulo Buchsbaum
  • 2,471
  • 26
  • 29
  • 2
    And they've told that kotlin will *"Drastically reduce the amount of boilerplate code"*... – user7860670 Jan 07 '20 at 16:24
  • 3
    It does compared to Java. It does not compared to lower-level languages at tasks higher-level languages are not designed to do. – Tenfour04 Jan 07 '20 at 17:06
5

You can have a function that gets the references of variables

var x = 10
var y = 20

fun main() {
    println("x=$x, y=$y") // x=10, y=20
    swap(::x, ::y)
    println("x=$x, y=$y") // x=20, y=10
}

fun <T> swap(firstRef: KMutableProperty0<T>, secRef: KMutableProperty0<T>) {
    val temp = firstRef.get()
    firstRef.set(secRef.get())
    secRef.set(temp)
}

and you can pass the references of properties of some class like this swap(someClass::x, someClass::y)

the only limitation is that you can't pass references of local variables which is not the end of the world.

if you don't like the messy syntax you can always define a typealias and make it pretty:

typealias Ref<T> =  KMutableProperty0<T>

fun <T> swap(firstRef: Ref<T>, secRef: Ref<T>) {
    ...
}
Mohsen
  • 1,246
  • 9
  • 22
3

I know that OP didn´t ask for this, but idiomatic Kotlin would look like:

var a = 1
var b = 2
a = b.also { b = a }
OliverE
  • 437
  • 5
  • 12
1

Seems like Kotlin behaves pretty much like Java does: Is Kotlin "pass-by-value" or "pass-by-reference"?

simple way to swap is make support class


private fun swap(pair: Pair) {
    pair.a += pair.b
    pair.b = pair.a - pair.b
    pair.a = pair.a - pair.b
}

private data class Pair(var a: Int, var b: Int)

fun main() {

    val pair = Pair(10, 5)
    swap(pair)
    println(pair)

}
Ludov Dmitrii
  • 425
  • 5
  • 9