Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutating function inside class

Consider this class in Swift:

class Zombie: Monster {
    var walksWithLimp = true

    final override func terrorizeTown()
    {
        town?.changePopulation(-10)
        super.terrorizeTown()
    }

    func changeName(name: String, walksWithLimp: Bool)
    {
        self.name = name
        self.walksWithLimp = walksWithLimp
    }
}

Zombie inherits the name field from the Monster class.

var name = "Monster"

Why does

fredTheZombie.changeName("Tom", walksWithLimp: true) 

work even if there is no mutating keyword before the function header?

like image 324
Bogdan Pop Avatar asked Jul 17 '16 15:07

Bogdan Pop


People also ask

Can we use mutating keyword in class?

If you mark a protocol instance method requirement as mutating, you don't need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations.

What is a mutating function?

What can a mutating function do? Essentially, a function that's been marked as mutating can change any property within its enclosing value. The word “value” is really key here, since Swift's concept of structured mutations only applies to value types, not to reference types like classes and actors.

How do you call a mutating function in Swift?

In order to modify the properties of a value type, you have to use the mutating keyword in the instance method. With this keyword, your method can then have the ability to mutate the values of the properties and write it back to the original structure when the method implementation ends.

Can you mutate a struct?

Structs are not copied on mutation. They may be mutated in-place. But every variable is a new copy (including passing the struct value as a function parameter). In functional languages values are truly immutable (so in order to change oven's temperature you need create a new oven in a new kitchen in a new house).


2 Answers

From The Language Guide - Methods:

Modifying Value Types from Within Instance Methods

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

You can opt in to this behavior by placing the mutating keyword before the func keyword for that method ...

Hence, we need to include the keyword mutating to allow a member (e.g. a function) of a value type to mutate its members (e.g. the member properties of a struct). Mutating a member of a value type instance means mutating the value type instance itself (self), whereas mutating a member of a reference type instance will not mean the reference of the reference type instance (which is considered self) is mutated.

Hence, since a class is a reference type in Swift, we need not include the mutating keyword in any of the instance methods of your Zombie class, even if they mutate the instance members or the class. If we were to speak of mutating the actual class instance fredTheZombie, we would refer to mutating its actual reference (e.g. to point at another Zombie instance).

[†]: As another example, we may use e.g. mutating getters (get); in which case we need to mark this explicitly as these are nonmutating by default. Setters (set), on the other hand, are mutating by default, and hence need no mutating keyword even if they mutate members of a value type.

like image 132
dfrib Avatar answered Dec 11 '22 02:12

dfrib


Without mutating func

struct Counter {
    let count: Int

    init(count: Int = 0) {
        self.count = count
    }

    // the functional approach
    func counterByIncrementing() -> Counter {
        let newCount = count + 1
        return Counter(count: newCount)
    }
}

var counter = Counter()
counter = counter.counterByIncrementing()

Mutating func

struct Counter {
    // this now has to be a var :/
    var count: Int

    init(count: Int = 0) {
        self.count = count
    }

    // the mutating keyword approach
    mutating func increment() {
        count += 1
    }
}

var counter = Counter()
counter.increment()

In class, all func are mutating. But for struct and enum we need to specify.

like image 36
Vinoth Anandan Avatar answered Dec 11 '22 03:12

Vinoth Anandan