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 implicitself
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)
:
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 structSelf 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
Detecting iOS Dark Mode Change
How to Implement Hash(Into:) from Hashvalue in Swift
Get Playground to Display All Loop Results
How to Prevent Actor Reentrancy Resulting in Duplicative Requests
Check Availability in Switch Statement
Pop to Root View Using Tab Bar in Swiftui
Swiftui MACos Nswindow Instance
Convert Swiftui View to Nsimage
Swiftui: How to Draw Filled and Stroked Shape
How to Convert Nsurl to String in Swift
Mutate Function Parameters in Swift
Show/Hide Password - How to Add This Feature
Using Environmentobject in Watchos