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?
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.
mutating
is not relevant for classes, it is only for value types, such as struct
and enum
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.
Another easy to understand example, verified in Swift 3 & 4
struct City
{
var population : Int
func changePopulation(newpopulation : Int) {
population = newpopulation //error: cannot modify property "population"
}
}
var mycity = City(population : 500)
mycity.changePopulation(newpopulation : 2000) //error: cannot modify property "population"
Solution
mutating func changePopulation(newpopulation : Int)