What Does the Swift 'Mutating' Keyword Mean

Mutating function inside class

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.

Is it possible to write mutating function in swift class?

In swift, classes are reference type whereas structures and enumerations are value types. The properties of value types cannot be modified within its instance methods by default. 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.

What is the more accurate difference between function overriding and function mutating? In swift particularly

Mutating

Swift structs are immutable objects meaning that you cannot change its properties within its functions. You need to explicitly mention that you agree to make changes to its properties by adding the mutating keyword in the function definition. However this mutating jargon is required only for value types in Swift - structs and enums.

struct MutatingExample {
var number: Int = 0

// Add 'mutating' to resolve the error
func changeNumber(changedNumber: Int) {
self.number = changedNumber // Error: Cannot assign to property: 'self' is immutable
}
}

Here is an useful post that might provide you more insights - What does the Swift 'mutating' keyword mean?

Reference types such as class do just fine and allow you to change the properties within their functions.

Override

Override is a concept used in inheritance. By that we can infer that override is applicable to reference types such as class and value type(struct/enums) are out of question.

As the name implies, we use the keyword to override an existing functionality, typically that of a super class. For example,

class Parent {
func getName() {
print("Parent")
}
}

class Child: Parent {
// Add override to resolve error
func getName() {
print("Child") // Error: Overriding declaration requires an 'override' keyword
}
}

Useful link: https://www.hackingwithswift.com/sixty/8/3/overriding-methods

Swift and mutating struct

The mutability attribute is marked on a storage (constant or variable), not a type. You can think struct has two modes: mutable and immutable. If you assign a struct value to an immutable storage (we call it let or constant in Swift) the value becomes immutable mode, and you cannot change any state in the value. (including calling any mutating method)

If the value is assigned to a mutable storage (we call it var or variable in Swift), you're free to modify the state of them, and calling of mutating method is allowed.

In addition, classes don't have this immutable/mutable mode. IMO, this is because classes are usually used to represent reference-able entity. And reference-able entity is usually mutable because it's very hard to make and manage reference graphs of entities in immutable manner with proper performance. They may add this feature later, but not now at least.

For Objective-C programmers, mutable/immutable concepts are very familiar. In Objective-C we had two separated classes for each concept, but in Swift, you can do this with one struct. Half work.

For C/C++ programmers, this is also very familiar concept. This is exactly what const keyword do in C/C++.

Also, immutable value can be very nicely optimised. In theory, Swift compiler (or LLVM) can perform copy-elision on values passed by let, just like in C++. If you use immutable struct wisely, it will outperform refcounted classes.

Update

As @Joseph claimed this doesn't provide why, I am adding a little more.

Structs have two kind of methods. plain and mutating methods. Plain method implies immutable (or non-mutating). This separation exists only to support immutable semantics. An object in immutable mode shouldn't change its state at all.

Then, immutable methods must guarantee this semantic immutability. Which means it shouldn't change any internal value. So compiler disallows any state changes of itself in a immutable method. In contrast, mutating methods are free to modify states.

And then, you may have a question of why immutable is the default? That's because it's very hard to predict the future state of mutating values, and that usually becomes the main source of headaches and bugs. Many people agreed that the solution is avoiding mutable stuffs, and then immutable by default was on top of wish list for decades in C/C++ family languages and its derivations.

See purely functional style for more details. Anyway, we still need mutable stuffs because immutable stuffs have some weaknesses, and discussing about them seems to be out of topic.

I hope this helps.

Is there any difference between mutating function and inout parameters in Swift?

mutating marks a method. inout marks a parameter. They are completely different things.

Methods marked with mutating can mutate self i.e. set properties of self, reassign self etc.

struct Foo {
var foo: Int

mutating func mutate() {
foo += 1 // this is mutating self
}
}

Parameters marked with inout basically become var variables, as opposed to let constants. You can change them, and the changes will also reflect on the caller's side.

func f(_ x: inout Int) {
x = 10
}

var a = 1
f(&a)
print(a) // 10

Why does this Swift struct require mutating ?

Yes it is the default behaviour for a struct or enum that instance methods can not modify a property since they are value type. So you need to use mutating to override this behaviour.

The way you define your property, var or let, is still relevant for if you can change it from a mutable instance method or directly or not.

Since your property is not private you can still do

var g = Game(map: [[1]])
g.map.append([2])

Does a mutating struct function in swift create a new copy of self?

Now does the existing struct in memory get mutated, or is self replaced with a new instance

Conceptually, these two options are exactly the same. I'll use this example struct, which uses UInt8 instead of Double (because its bits are easier to visualize).

struct Point {
var x: UInt8
var y: UInt8

mutating func add(x: UInt8){
self.x += x
}
}

and suppose I create a new instance of this struct:

var p = Point(x: 1, y: 2)

This statically allocates some memory on the stack. It'll look something like this:

00000000  00000001  00000010  00000000
<------^ ^------^ ^------^ ^----->
other | self.x | self.y | other memory
^----------------^
the p struct

Let's see what will happen in both situations when we call p.add(x: 3):

  1. The existing struct is mutated in-place:

    Our struct in memory will look like this:

    00000000  00000100  00000010  00000000
    <------^ ^------^ ^------^ ^----->
    other | self.x | self.y | other memory
    ^----------------^
    the p struct
  2. Self is replaced with a new instance:

    Our struct in memory will look like this:

    00000000  00000100  00000010  00000000
    <------^ ^------^ ^------^ ^----->
    other | self.x | self.y | other memory
    ^----------------^
    the p struct

Notice that there's no difference between the two scenarios. That's because assigning a new value to self causes in-place mutation. p is always the same two bytes of memory on the stack. Assigning self a new value to p will only replace the contents of those 2 bytes, but it'll still be the same two bytes.

Now there can be one difference between the two scenarios, and that deals with any possible side effects of the initializer. Suppose this is our struct, instead:

struct Point {
var x: UInt8
var y: UInt8

init(x: UInt8, y: UInt8) {
self.x = x
self.y = y
print("Init was run!")
}

mutating func add(x: UInt8){
self.x += x
}
}

When you run var p = Point(x: 1, y: 2), you'll see that Init was run! is printed (as expected). But when you run p.add(x: 3), you'll see that nothing further is printed. This tells us that the initializer is not anew.

What does it mean if a mutating function setting it's self equals to another function

I'm assuming that this fragment is in a struct rather than a class.

self.normalized() makes a copy of self and divides the copy's components by its length and then returns the copy. self is not affected.

self.normalize() gets a normalised version of self and then replaces self by the copy. So it changes in place.

Under the hood, every member function passes self as an implicit argument. i.e. to the compiler the declaration looks like this:

func normalised(self: SCNVector3) -> SCNVector3

Putting mutating on the front of a function definition makes the hidden argument inout

func normalise(self: inout SCNVector3)

So, if you have

var a = SCNVector3(3, 4, 0)
let b = SCNVector3(4, 3, 0)
let c = b.normalized()
a.normalize()

After that code, c would be (0.8, 0.6, 0) and a would be (0.6, 0.8, 0). b would be unchanged.

Note that a has to be declared with var because it is changed in place by normalise()

Edit

In the comments khan asks:

What i am not able to understand is why do we have to create a func again we can use "func normalized"

The point being made is why can't we do something like this:

    var a = SCNVector3(3, 4, 0)
a = a.normalized()

and not have the normalise() function at all?

The above will have exactly the same effect as a.normalize() and, in my opinion[1], is better style, being more "functional".

I think a.normalize() exists only because it is common in Swift to provide both forms of the function. For example, with sets you have both union() and formUnion(): the first returns the union of one set with another, the second replaces a set with the union of itself and another set. In some cases, the in place version of the function may be more efficient, but not, I think, with this normalize function.

Which you choose to use is a matter of your preference.


[1] Actually, the better style is

let a = SCNVector3(3, 4, 0).normalized()

What happens when a Class conforms to a protocol, which contains mutating function?

I don't see what the "confusion" is. You've elucidated the rules beautifully! A struct may implement a protocol's mutating function as nonmutating, but it may not implement a protocol's nonmutating function as mutating. Once you've said those rules, there's nothing to be "confused" about. The rules are the rules.

Classes don't have mutating functions so your investigations there are sort of irrelevant. If you had declared your protocol as a class protocol, your mutating annotation in the protocol would have been illegal.



Related Topics



Leave a reply



Submit