Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass an Integer by Reference in Kotlin

Tags:

kotlin

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.

like image 632
john doe Avatar asked Aug 01 '18 17:08

john doe


People also ask

Can you pass by reference in Kotlin?

Since no assignment is possible for function parameters, the main advantage of passing by reference in C++ does not exist in Kotlin.

How do you pass a value in Kotlin?

In Kotlin, You can pass a variable number of arguments to a function by declaring the function with a vararg parameter. a vararg parameter of type T is internally represented as an array of type T ( Array<T> ) inside the function body.


3 Answers

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.

like image 133
Paulo Buchsbaum Avatar answered Oct 14 '22 10:10

Paulo Buchsbaum


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>) {
    ...
}
like image 24
Mohsen Avatar answered Oct 14 '22 09:10

Mohsen


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 }
like image 39
OliverE Avatar answered Oct 14 '22 09:10

OliverE