Reputation: 43
If I clear()
my local list (mList
) it also clearing companion
's Mutablelist (list
)
Why this happening explanation's are welcome :)
I've a class with companion
like this :
class Data {
companion object {
var list:MutableList<String> = ArrayList()
}
}
If I create my local list something like this :
fun main() {
// some dummy data
Data.list.add("Lion")
Data.list.add("Cat")
Data.list.add("Dog")
Data.list.add("Cheetah")
// my local mList
val mList = Data.list
println("Before Clearing : mList = $mList\n list = ${Data.list}")
mList.clear()
println("After Clearing : mList = $mList\n list = ${Data.list}")
}
OutPut
Before Clearing : mList = [Lion, Cat, Dog, Cheetah]
list = [Lion, Cat, Dog, Cheetah]
After Clearing : mList = []
list = []
As You can see in output if I clear()
local mList
it is clearing companion
's list Why it is ?
if I do this same with some other things like double
it is not happening like this example -
// same Data class's
...
var pi = 3.14
...
If change local mPi
it doesn't change pi
:
var mPi = Data.pi
println("Before Assigning to New value mPi = $mPi and pi = ${Data.pi}")
mPi = 319.12
println("After Assigning to New value mPi = $mPi and pi = ${Data.pi}")
2nd Output
Before Assigning to New value mPi = 3.14 and pi = 3.14
After Assigning to New value mPi = 319.12 and pi = 3.14
Link of Kotlin Playground
Why it is happening? I'd like to know :)
Upvotes: 0
Views: 839
Reputation: 93834
You compared changing the contents of a list with changing the value of a variable, which are not the same thing. In your example, mPi
is first assigned to point at the value of Data.pi
and then it’s changed to point at some other Double. You aren’t doing anything to modify the Double itself, only what the local variable mPi
is pointing to.
When you do val newList = Data.list
, you are declaring the variable to point to the same list instance as in Data. Then you modify the contents of that same list. Since both variables are pointing at the same instance, you will observe the same changes if you inspect the instance via either variable. Notice you did not reassign the variable’s value using newList =
like you did in the pi
example, which is why these are not analogous actions.
In short, with the pi example, you have two Double instances and were switching between them by changing the value of a variable. With the list example, you have only one MutableList instance that you are internally mutating.
Notably, primitive type classes are all immutable so there’s no way you could modify their contents even if you wanted to. They don’t have functions you can call on them to change the value they represent. In Kotlin you rarely have to think about the distinction between primitive classes and other classes unless you’re optimizing code performance.
Upvotes: 1
Reputation: 1087
In order to understand what is going on here you need to know how values are saved in memory. All objects that are created using the new
keyword (not needed in Kotlin), are stored in heap memory whereas all primitive data types are in stack memory.
Consider the following code
val list: MutableList<String> = ArrayList()
What is happening here is that a new object of ArrayList
is being created in the heap. The variable list
can be considered as a box which holds the location where the actual object is created. You can imagine the variable holding a value of 0x7800abd12
.
Now what happens, when you create a new variable and assign the one that you created above.
val newList = list
Here, you assigned whatever value the variable list
had to the variable newList
. What this did was in fact save the memory address 0x7800abd12
in the variable newList
. Remember, the value is the location where the actual list is created. Now, if the user accesses either list
or newList
, they will be taken to the object at the given memory address. Since both variables have the same address, any change made to either of the two variables will reflect for both of them.
But why doesn't this behaviour reflect when we are using primitive data types. Remember, I mentioned that primitive data types are stored on the stack rather than heap. Consider this example
val pi = 3.142
In this case, the variable pi
actually holds the value 3.142
rather than a memory location. Now, when you assign it to another variable, the new variable also holds the value rather than a memory location.
val newPi = pi
Here newPi
holds the value 3.142
. If you change newPi
to some other value, it will only update the variable newPi
and won't update the variable pi
.
In order to learn more about this you can check out this thread.
Upvotes: 2