Start learning free

LESSON 59 OF 415 · STRINGS I

String Immutability in Swift: Why name[0] = "A" Fails

Lesson Read the full explanation

In Swift, you cannot change a single character of a string through its index: a String's subscript can only read characters (it is get-only).

For example, the following code:

var message = "Jello world"

message[message.startIndex] = "H"

does not compile: cannot assign through subscript: subscript is get-only.


Variable can still be changed:

Note that this does not mean that message cannot be changed, just that its characters cannot be replaced one at a time through an index.

Unlike strings in many other languages, a Swift string declared with var can be changed in place with methods such as append, insert or replaceSubrange. A string declared with let cannot be changed at all.

The simplest way to change message is to reassign it with a new string, like any other variable:

var message = "Jello world"

message = "Hello world"

print(message)

This code would output:

Hello world

Instead of trying to alter one character of the first string, this code gives message a whole new value ("Hello world").


Assignment
Follow the Coding Tutorial and let's practice with string immutability!


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    SWIFT · STRINGS I

    String Immutability in Swift, explained

    What the rule is

    In Swift you can't replace one character of a string through its index. A string's subscript can only read characters; it is get-only. This code doesn't compile:

    var name = "bndrei"
    name[name.startIndex] = "A"
    
    error: cannot assign through subscript: subscript is get-only
    

    The same error appears when you write an integer position, name[0] = "A", as the starter code of this lesson does. Even with the right kind of index, assignment through the subscript is not allowed.

    Part of the reason is that a Swift string is a sequence of Unicode characters, and one character can take a different number of bytes than the next. Replacing one in place could mean shifting everything after it, so Swift asks you to build the new text explicitly instead.

    What can change

    This does not mean a string variable is frozen. It means characters can't be swapped one at a time by position. Two things decide what you can do:

    • var or let. A string declared with var can be reassigned, and it can also be changed in place with methods such as append, insert and replaceSubrange. A string declared with let can't change at all, and trying to call append on it is a compile error.
    • Value semantics. A String is a value type. Assigning it to another variable gives that variable its own independent copy, so changing one never affects the other.
    let fixed = "Hello"
    var copy = fixed
    copy.append("?")
    print(fixed, copy)
    
    Hello Hello?
    

    Three ways to change a string

    1. Reassign a whole new value

    The simplest fix is to give the variable a new string, built from pieces of the old one:

    var message = "Jello world"
    message = "Hello world"
    print(message)
    
    Hello world
    

    2. Edit in place with a mutating method

    replaceSubrange takes a range of indices and the text to put there. Replacing the range that holds only the first character changes just that character:

    var message = "Jello world"
    message.replaceSubrange(message.startIndex...message.startIndex, with: "H")
    print(message)
    
    Hello world
    

    3. Work on an array of characters

    An Array can be changed by position. Convert the string with Array(...), change the element, and convert back with String(...):

    var chars = Array("Jello")
    chars[0] = "H"
    print(String(chars))
    
    Hello
    

    The exercise

    The variable name holds "bndrei Chiriac", and it should hold "Andrei Chiriac". Only the first character is wrong, but name[0] = "A" can't be compiled. To fix it:

    1. Take everything after the first character with name.dropFirst(). That gives a Substring with the value "ndrei Chiriac".
    2. Convert it with String(...) to get a real String.
    3. Put "A" in front with +, which joins two strings into a new one, and assign the result back to name.
    var name = "bndrei Chiriac"
    
    // Change code below:
    
    name = "A" + String(name.dropFirst())
    print(name)
    
    Andrei Chiriac
    

    The right-hand side is evaluated first, using the old value of name, and only then is the new string stored in the variable. The old string isn't modified; name just points to a new value.

    Common mistakes

    • Trying to assign through the subscript. name[index] = "A" never compiles, whatever the index.
    • Using let. The fix above reassigns name, so the variable must be declared with var.
    • Forgetting String(...). dropFirst() returns a Substring, and assigning a Substring to a String variable is a compile error (cannot assign value of type 'Substring' to type 'String'). Wrap it in String(...).
    • Expecting a copy to change too. After var copy = original, editing copy leaves original as it was.

    Key takeaways

    • A string's subscript is get-only: you can read a character by index, but never assign to it.
    • A var string can be reassigned or changed with methods such as append, insert and replaceSubrange. A let string can't change.
    • To change one character, build a new string from pieces, as in "A" + String(name.dropFirst()).
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free