104

As I know Java is pass-by-value from this post. I am from Java background I wonder what Kotlin is using for passing values in between. Like in Extensions or Methods etc.

Rahul Khurana
  • 8,577
  • 7
  • 33
  • 60
  • 10
    I think it's fair to say that everything works the same way as in Java. – zsmb13 Jun 13 '17 at 07:33
  • i have read the differences between kotlin and java from various blogs, is there any kind of big internal change which needs to be covered? – Rahul Khurana Jun 13 '17 at 07:38
  • Probably not, Kotlin is compiled to bytecode in a pretty straightforward way in general. – zsmb13 Jun 13 '17 at 07:40
  • Ok thanks i understand. I am curious to know why google has announced kotlin as first language for android – Rahul Khurana Jun 13 '17 at 07:42
  • @Pelocho consider converting your comment to an answer. – Kirill Rakhman Jun 13 '17 at 08:35
  • 2
    @RahulKhurana I guess mostly because of resulting cleaner code and almost seamless Java-interop as well as low entry barrier, which result in very dynamic expansion among devs. And it was "first-class language", not "first language", which probably will be still Java. – Antek Jul 10 '17 at 14:30

8 Answers8

74

Every time I hear about the "pass-by-value" vs "pass-by-reference" Java debate I always think the same. The answer I give: "Java passes a copy (pass-by-value) of the reference (pass-by-reference)". So everyone is happy. I would say Kotlin does the same as it is JVM based language.

UPDATE

OK, so it's been a while since this answer and I think some clarification should be included. As @robert-liberatore is mentioning in the comments, the behaviour I'm describing is true for objects. Whenever your methods expect any object, you can assume that the JVM internally will make a copy of the reference to the object and pass it to your method. That's why having code like

void doSomething(List<Integer> x) {
  x = new ArrayList<Integer>()
}

List<Integer> x = Arrays.asList(1, 2, 3);
doSomething(x);
x.length() == 3

behaves like it does. You're copying the reference to the list, so "reassigning it" will take no effect in the real object. But since you're referring to the same object, modifying its inner content will affect the outer object.

This is something you may miss when defining your attributes as final in order to achieve immutability. You won't be able to reassign them, but there's nothing preventing you from changing its content

Of course, this is true for objects where you have a reference. In case of primitives, which are not a reference to an object containing something but "something" themselves, the thing is different. Java will still make a copy of the whole value (as it does with the whole reference) and pass it to the method. But primitives are just values, you can't "modify its inner values". So any change inside a method will not have effect in the outer values

Now, talking about Kotlin

In Kotlin you "don't have" primitive values. But you "do have" primitive classes. Internally, the compiler will try to use JVM primitive values where needed but you can assume that you always work with the boxed version of the JVM primitives. Because of that, when possible the compiler will just make a copy of the primitive value and, in other scenarios, it will copy the reference to the object. Or with code

fun aJvmPrimitiveWillBeUsedHere(x: Int): Int = x * 2

fun aJvmObjectWillBeUsedHere(x: Int?): Int = if (x != null) x * 2 else 1

I'd say that Kotlin scenario is a bit safer than Java because it forces its arguments to be final. So you can modify its inner content but not reassign it

fun doSomething(x: MutableList<Int>) {
    x.add(2)                  // this works, you can modify the inner state
    x = mutableListOf(1, 2)   // this doesn't work, you can't reassign an argument
}
Alberto S.
  • 7,409
  • 6
  • 27
  • 46
  • 44
    Okay, I'll be that guy, because someone has to be: Java passes in the actual values of primitives, not references. A better way of understanding this is that it passes the value, and for Objects the value is a reference. – Bob Liberatore Jan 10 '20 at 21:29
  • 1
    @RobertLiberatore Are you arguing that there's no such thing as pass by reference? Because passing by reference is just passing the pointer as a value (copied). – DoubleTrouble Nov 02 '20 at 21:35
  • 1
    I'm not arguing. Java defines itself as pass by value in it's specifications: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.1 But no, I would not make that argument. Passing *by* reference is not the same as passing *a* reference. In pass by value, if you pass in a reference, you get the value of the reference. In pass by reference, if you pass in a reference, you get a reference to a reference. This latter has no good analog in Java, and that may be the source of confusion. – Bob Liberatore Nov 04 '20 at 20:40
  • 1
    With Kotlin 1.5, I believe the statements about "primitive" classes also apply to value classes. – Tenfour04 Jul 13 '21 at 22:04
  • 2
    @BobLiberatore You just summarized it perfectly in 2 sentences – Farid Jan 31 '22 at 17:43
56

It uses the same principles like Java. It is always pass-by-value, you can imagine that a copy is passed. For primitive types, e.g. Int this is obvious, the value of such an argument will be passed into a function and the outer variable will not be modified. Please note that parameters in Kotlin cannot be reassigned since they act like vals:

fun takeInt(a: Int) {
    a = 5
}

This code will not compile because a cannot be reassigned.

For objects it's a bit more difficult but it's also call-by-value. If you call a function with an object, a copy of its reference is passed into that function:

data class SomeObj(var x: Int = 0)

fun takeObject(o: SomeObj) {
    o.x = 1
}

fun main(args: Array<String>) {
    val obj = SomeObj()
    takeObject(obj)
    println("obj after call: $obj") // SomeObj(x=1)
}

You can use a reference passed into a function to change the actual object.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
  • 1
    For the primitive type parameter...if you can't re-assign it, then what's the point of a pass-by-value?? – shinvu Aug 15 '20 at 07:55
  • 1
    @shinvu - I think the reason is that 'pass-by-value' handles immutability of a variable declared outside of the function call, and 'function parameter is val' handles immutability of the parameter used inside the function call. So at no time is the variable in question allowed to be changed once set, thereby avoiding "side effects" (change to variable outside the function cascading to affect state inside the function, unexpectedly). This is what makes a function "pure" in a functional programming sense. – Steve T Sep 12 '20 at 18:43
34

The semantics is identical to Java.

In Java, when you have an instance of an object, and you pass it to a method, that method can change the state of that object, and when the method is done, the changes would have been applied to the object at the call site.

The same applies in Kotlin.

hasen
  • 161,647
  • 65
  • 194
  • 231
10

For primitives value is passed, and for non-primitives a reference to the object is passed. I'll explain with an example:

The code:

    fun main() {
        var a = 5
        var b = a
        a = 6
        println("b = $b")
    }

prints: b = 5

Kotlin passes the value of a to b, because a is a primitive. So changing a afterwards won't impact b.

The code:

    fun main() {
        var a = Dog(5)
        var b = a
        a.value = 6
        println("b = ${b.value}")
    }

    class Dog (var value: Int)

prints b = 6, because this time a is not a primitive and so the reference to the object (Dog) was passed to b and not its value. Therefore changing a would affect all objects that point to it.

Amir Golan
  • 378
  • 3
  • 8
7

In Java primitive types like int, float, double, boolean are passed to a method by value, if you modify them inside the receiver method they doesn't change into the calling method. But if the property/variable type isn't a primitive, like arrays of primitives or other classes when they are changed inside the method that receive them as parameter they also change in the caller method. But with Kotlin nothing seems to be primitive, so I think all is passed by reference.

user2604769
  • 79
  • 1
  • 1
3

This might be a little bit confusing. The correct answer, IMHO, is that everything passes by reference, but no assignment is possible so it will be similar to passing by value in C++.

Note that function parameters are constant, i.e., they cannot be assigned.

Remember that in Kotlin there are no primitive types. Everything is an object. When you write:

var x: Int = 3
x += 10

You actually create an object of type Int, assign it the value 3, and get a reference, or pointer, named x. When you write

x += 10

You reassign a new Int object, with the value 13, to x. The older object becomes a garbage (and garbage-collected).

Of course, the compiler optimizes it, and creates no objects in the heap in this particular case, but conceptually it is as explained.

So what is the meaning of passing by reference function parameters?

  • Since no assignment is possible for function parameters, the main advantage of passing by reference in C++ does not exist in Kotlin.
  • If the object (passed to the function) has a method which changes its internal state, it will affect the original object.
    • No such method exists for Int, String, etc. They are immutable objects.
  • No copy is ever generated when passing objects to functions.
Asher Stern
  • 2,476
  • 1
  • 10
  • 5
-1

Bear in mind, am quite new to Kotlin. In my opinion, primitives are passed-by-value, but objects are passed-by-reference.

A primitive passed to a class works by default, but if you pass an object from a list, for example, and that object changes, the class object changes too. Because, in fact, it is the same object.

Additionally, if objects gets removed from the list, the class object IS STILL A REFERENCE. So it can still change due to references in other places.

Example below explaines. You can run it here.

fun main() {
   val listObjects = mutableListOf(ClassB(), ClassB(), ClassB())
   val listPrimitives = mutableListOf(111, 222, 333)

   val test = ClassA()

   test.ownedObject = listObjects[0]
   test.ownedPrimitive = listPrimitives[0]

   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)

   listObjects[0].isEnabled = true
   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)

   listPrimitives[0] = 999
   println("ownedObject: " + test.ownedObject.isEnabled +", ownedPrimitive: " + 
   test.ownedPrimitive)
}

class ClassA {
  var ownedObject: ClassB = ClassB()
  var ownedPrimitive: Int = 0
}

class ClassB {
  var isEnabled = false
}
gq97a6
  • 109
  • 1
  • 4
-2

Since Kotlin is a new language for JVM, like Java it is pass-by-value. The confusing part is with object, at first it looks like that it is passed-by-reference but the actuality is that the reference/pointer itself is pass-by-value (a copy of a reference is passed to a method) hence when a method receives a reference to an object, the method can manipulate the original object.

Bitwise DEVS
  • 2,858
  • 4
  • 24
  • 67