Mutating Functions in Swift Structs

I’ve started working a lot more with Swift Structs, especially as I’m learning more about functional programming. I remember when Swift first came out, I was super confused about why the compiler made me insert the “mutating” keyword for my functions in structs. However, now after reading a bunch about value vs reference types, it’s starting to make a lot of sense.

Throughout this post, I’ll be using a simple Rectangle struct:

struct Rectangle {
    var width = 1
    var height = 1
}

The Mutating Keyword

Let’s say you want to add an area function to your struct:

struct Rectangle {
    var width = 1
    var height = 1
    
    func area() -> Int {
        return width * height
    }
}

It’s just as you expect! This area function multiplies the existing width and height of the rectangle and returns the result. The key here is that this function does NOT change the width or height variables – it only uses the existing values.

In contrast, let’s say we wanted to have a function that scales the rectangle:

struct Rectangle {
    var width = 1
    var height = 1

    mutating func scaleBy(value: Int) {
        width *= value
        height *= value
    }
}

Notice that this function actually changes the width and height variables of the rectangle. So this is where you have to use the mutating keyword – when you’re actually changing the variables in your struct!

Using A Mutating Function

So the first time I wrote a mutating function, I was surprised (and very frustrated) when this happened:

Mutating Function Error Swift

As you can see, this compiler error is super confusing and unhelpful if you don’t fully understand how the mutating concept works.

The “fix” (aka correct way to work with / use mutating functions) is to make your struct a variable:

Struct Variable Swift

Tadaaaa! It magically works! I wonder why…

Why Var?

Remember, a Struct is a value type. In other words, it’s supposed to be immutable. That’s confusing, considering it appears like we’ve added a function that mutates the internals of our struct. Yep, the mutating keyword is starting to make sense now.

By having to make our struct a variable instead of a constant to use the mutating function, Swift is giving us a very strong hint as to what is happening. When we call our mutating scaleBy function, it actually replaces the original rectangle stored in the myRect variable with a brand new rectangle (with the new scaled width and height in our case).

As I was trying to understand this more, I remembered that @jspahrsummers mentioned something on the topic at the Functional Swift Conference. I recommend watching his whole talk, but if you want to get a better understanding of the mutating struct behavior, watch this video starting at the 12:30 mark.

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • Neeraj Kumar

    Hi I think following would be rather a simple way to understand.

    When studying difference between value (struct )and reference(class) types we got examples where a immutable value type and any of its properties cannot be mutated but with reference types you can change its properties for example –

    struct Name {

    var firstName

    var secondName
    }

    class Name {

    var firstName

    var secondName

    // A counstructor.
    }

    let aStruct = Name(firstName:”Neeraj”, secondName:”Kumar”)

    let aClass = Name(firstName:”Neeraj”, secondName:”Kumar”)

    aStruct.firstName = “Hello” // error
    aClass.firstName = “Hello” // No error.

    Because a value type (struct) defined with a ‘let’ is completely immutable then of course either outside the struct (like above) or inside struct you cant mutate.
    Also while defining a struct Swift doesnt know if you are gonna use it as let or var or both so there is no point of error beforehand.

    • Josh

      That was helpful — thanks.

  • Pingback: Swift Programming Language Weekly | Jan-12-2015 - Swift Tutorial hq()

  • Pingback: Conveniently Transforming Immutable Types in Swift()

  • Samer

    Thanks for making my life easier and clarifying/simplifying this topic.

  • AngryNerd

    Actually, it’s more in keeping with the ideas of functional programming to add a method that creates a *new* struct from the old one (i.e. both structs stay immutable):

    struct Rectangle {
    let height:Float
    let width:Float

    init(w:Float, h:Float) {
    height = h
    width = w
    }

    func scaledBy(f:Float) -> Rectangle {
    let ww:Float = width * f
    let hh:Float = height * f
    return Rectangle(w:ww, h:hh)
    }
    }

    let r1:Rectangle = Rectangle(w:100,h:50)
    let r2:Rectangle = r1.scaledBy(1.5)

    • Tim

      Perhaps, but Swift never claimed to be a functional programming language. You’re duplicating some built-in functionality (structs are already copy-on-write internally). All you get is the ability for r2 to be “let”-immutable.

      You wrote more code, and in a non-idiomatic way for the language. You could have just said “let r3 = r2” if you wanted an immutable version of second rectangle. Is that style worth it?

      In my book, it’s not. You should try to use the features of the language, not fight them by tring to imitate features of other languages.

  • Prasad

    I’m experiencing some weird behavior when working with Objective C – Swift interoperability. I have a model called PhotoAlbum(class) which holds an array of Photos(struct). Each Photo has a mutating function which updates image property of the photo. But, I don’t see the mutation happening in the expected way. In my use case, I initialized the PhotoAlbum class from the objective c method, called mutating function on each photo struct inside that album and then tried accessing each photo value. Now, I still see the struct values the same as I had when I initialized album. Any thoughts what might be going wrong?

    • Vince O’Sullivan

      (Six months later.) I assume that you’re looping through the array of Photos in Swift in a manner similar to: …for photo in photos… If so, then each photo is extracted as an immutable object (i.e. let not var) meaning that mutable functions will not work.

  • Dan

    I have a class method that in the current way of design, has to modify the incoming dictionary marked with “inout” for that purpose.

    Unfortunately you cannot use mutating for a class method, thus basically I’m not allowed to be able to change the passed dictionary?

    • Dan

      I was wrong.. After cleaning the project everything worked fine) And there is no need for mutating, just inout is enough

    • Instead of mutating or using inout, just return a branch new dictionary and reassign.

  • Andrew Aquino

    wow this was super helpful, i’ve been struggling with differentiating the idea of structs vs classes, thanks alot natasha

  • Fernando Fernandes

    Nice writing. Thanks.

  • Isuru Nanayakkara

    Thanks for the short and sweet explanation on this.