Reputation: 1562
I'm trying to learn Kotlin by reading its documentation. in the documentation there is a section about string. in that section it says:
Strings are immutable. Once you initialize a string, you can't change its value or assign a new value to it. All operations that transform strings return their results in a new String object, leaving the original string unchanged.
and tries to show that with an example:
fun main() {
val str = "abcd"
println(str.uppercase()) // Create and print a new String object
println(str) // the original string remains the same
}
I have a problem with the part that says:
the value of strings can't change after initializing.
but when I change the val
to var
I easily can change the value of the string.
so what the documentation means by saying the value of string can't be changed? we know that val
makes variables immutable, not just for strings.
Upvotes: 1
Views: 678
Reputation: 42481
It looks like you’re confused by two different things:
So to start with immutability: When you create an object it occupies some place in memory and contains “abcd” in your example.
The immutability means that you can’t change anything in this memory area, for example it’s impossible to make those bytes in memory to hold a string “abcE”. In general immutability means that you cannot change an internal state of the object after it has been created. This is a Design decisions of people who have developed a String class. They could easily provide API for changing the state (setters for example) but they chose to avoid doing so for many reasons which are beyond the scope of this question.
Now as for reference management:
Usually you don’t just create a String (which is still immutable) but also maintain a reference to it so that you could address it from your program.
There are two types of reference which confuse you.
If you define a reference with a val
keyword - this means that you won’t be able to “point” this reference to any other object, on the other hand, if you work with var
keyword, its possible to assign another object to that reference:
val s = “abc”
s=“def” // impossible
var k = “abc”
k = “def” // ok
Upvotes: 4
Reputation: 2345
To explain in one sentence , String value remains immutable but the string variable is mutable
.
Consider two string val a = "123" and val 2= "123" , then instead of creating two instances in the string pool , it creates only one instance and returns that instance to both the variables . String pool is an storage area in the heap memory. So hence ,when a string is created and if the string already exists in the pool, the reference of the existing string will be returned, instead of creating a new object and returning its reference. If string is not immutable, changing the string with one reference will lead to the wrong value for the other references. So when you change the value of one variable , it searches in the heap whether the value exist , if not it creates a new value in the heap else derives it from already existing one .
Upvotes: 1
Reputation: 271575
but when I change the
val
tovar
I easily can change the value of the string.
No, you cannot easily do that. Suppose you had:
var str = "foo"
This is not changing the value of the string "foo"
:
str = "bar"
You are just taking another instance of String
and putting it inside the property str
.
Notice that there is a difference between "the string" and "the property". "The string" refers to the instance of the String
class that you created by doing "foo"
. That instance is immutable. You cannot do anything to it to make that same instance have a different sequence of characters than f, o, o. This is because the String
class provides no public members that do this, and this is what the documentation was referring to when it says "String
is immutable".
On the other hand, "the property" is the str
that you declared by saying var str = ...
, and it is mutable. It stores instances of String
s, and you can change what instances it stores. But you can't change the strings themselves, once they are created.
Compare this with lists. List
is immutable, yet you can still do:
var myList: List<Int> = listOf(1, 2, 3)
Now suppose you want to remove all 3s in the list. You must create a new list:
// "filter" creates a new list
myList = myList.filter { it != 3 }
because List
is immutable, and it does not have any methods that does this without creating a new list. If myList
were a MutableList
, however, you could have done:
// this does not create a new list
myList.removeIf { it == 3 }
There is no MutableString
though :)
Upvotes: 7
Reputation: 2930
You are confusing the reference to the String
with the instance of the String
.
For a value to change, it's inner state must change. For a string object, once it is instantiated, it is never changed. However any references on that String
may be reassigned another String
instance, if they are themselves mutable.
val s = "My String"
var t = s
t = t + " Stuff"
println(s) // yields "My String"
Not only can no operator change the inner state of the String
, but also no method on the String
.
E.g. there exist languages, where you can do the following:
// note, this is pseudocode, and *not* kotlin semantics
final String someString = "Some String";
someString.cutFromEnd(" String");
println(someString); // could yield "Some" in some language.
Upvotes: 1