why we have to make function explicitly mutating in Structures in Swift? - swift

Why we have to make function explicitly mutating in Structures in Swift?
I want to understand behind the scene concept of this.
Can anyone explain how does it work?
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"
As per Apple Documentation "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."
Why it's not allowed to change properties of structures(value type) without mutating where as same is not the case with reference type?

Structs are value types and hence when you mutate any instance properties of a struct, you actually mutate the struct instance itself. This is why when you have a function that mutates any instance properties of the struct, you explicitly need to mark that function mutating, because calling the function mutates the struct instance itself too.
For more information, you should read the Methods chapter of the Swift Book, because it explains this behaviour in detail.

Related

Why does closure capture reference while function does not? Also, why "lazy" keyword is required for closure declaration?

I experimented it with the following code in Xcode Playground:
class X {
var a = 3
init(a: Int) {
self.a = a
}
deinit {
print("\(self.a) is deallocated.")
}
func returnX() -> Int {
return self.a
}
lazy var anotherReturnX: () -> Int = {
return self.a
}
}
var e: X? = X(a: 6)
print(e!.returnX())
e = nil // prints "6 is deallocated."
var f: X? = X(a: 7)
print(f!.anotherReturnX())
f = nil // prints nothing
From the above code, I can see that no reference is captured in the function returnX(), thus e is deallocated once I set e to nil. However, a reference is captured in the closure anotherReturnX(), thus f is not deallocated. Apparently, this implies that a closure captures references while a function does not.
Additionally, when I first type out the code, I didn't include lazy keyword before the closure declaration, as I thought it would be unnecessary to do so. However it triggers a compile-time error. I infer that since the closure can only be accessed after instantiation, it must access to the instantiated self. But since what I am declaring here is effectively an "anonymous function", why would the closure access to self during instantiation anyway?
After putting in some thoughts, I found more contradictions. For instance, I understand that a reference is captured when a closure is called. However, during initialisation of X, I am simply assigning a closure to a variable without calling it, same as the declaration of other instance properties. Thus the closure should not do anything during initialisation, and compiling the code without keyword lazy should be fine. But compilation fails. I am not sure what goes wrong in my understanding.
I have read some related articles, such as strong/weak reference, retain cycle, lazy stored property. However, many explain "what happens" and do not say much about "why".
So other than the question raised in the title, I would also like to clarify, what makes function and closure different from each other such that the above situation happens?
Update:
The fact that closure captures reference while function does not is further "enforced" on me, since, according to the Xcode Compiler, I can rewrite return self.a as return a in returnX(), but I cannot do so in anotherReturnX. As such, I guess I would have to accept that, although function and closure are similar because each of them is "a bundle of functionalities", function is different from closure that it does not capture references. If I were to go deeper in the reason behind this, it would probably involve the design of Swift itself?
However, I still cannot understand why lazy keyword is required for closure declaration.
lazy var anotherReturnX: () -> Int = {
return self.a
}
The self here is a strong self.
When an object references another object strongly, ARC cant deallocate so a retain cycle is created. The reference should be weak to avoid a retain cycle by creating weak self inside the block.
lazy var anotherReturnX: () -> Int = { [weak self] in
return self?.a
}
returnX is a method of the class. Methods don't capture variables. self is an implicit local variable in methods, that is implicitly passed to the method when the method is called.
anotherReturnX is a property that is assigned a closure lazily. That closure captures outside variables that are used within it, including self. That capturing creates a strong reference from the closure to the X instance, which, combined with the strong reference from the X instance to the closure, creates a retain cycle.

What does the Swift 'mutating' keyword mean?

Why must I insert mutating before implementing a method on a struct when adopting protocols?
Why don't I need mutating when I do the same thing in a class?
The mutating keyword is only required if you are changing any state contained within the struct. Since Swift structs are immutable objects, calling a mutating function actually returns a new struct in-place (much like passing an inout parameter to a function). The mutating keyword lets callers know that the method is going to make the value change. The best way to conceptualize this is to think of your struct the same as you would a number: if you perform the operation 4 + 1, 4 doesn’t become 5, you’ve just gotten a new value after performing the operation. Mutating functions operate on the same principle. You cannot call mutating functions on constants (e.g. let someStruct = SomeStruct()), because that would be the same thing as trying to assign the constant to a new value. Because of this behavior mutating functions can only be performed on variables (e.g var someStruct = SomeStruct()).
Being the value type structs are immutable. Meaning other variables can not change the values for instance of structure at any given point.
The mutating word is required for changing the values of self variables inside structure's function ONLY.
For. e.g
struct MyStruct {
var abc: String = "initila value"
func changeValue() {
abc = "some other value". //Compile time error: Cannot assign to property: 'self' is immutable. Mark method 'mutating' to make 'self' mutable.
}
}
Here as we are trying to change value of variable abc inside function declared in struct itself, we get the compile time error.
So here we need to make function mutating to make change value inside structure. Hence the correct code will be:
struct MyStruct {
var abc: String = "initila value"
mutating func changeValue() {
abc = "some other value"
}
}
EDIT:
When declaring protocol, it can be declared commonly for reference and value types, so these kind of protocols itself declares the functions as mutating so that it can be adopted by both classes and structures.
Since being reference type the mutating keyword is removed (or we can say not required) in the classes, but for structures being value types the mutating keyword is required.
From the docs:
If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.
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.
Reference
I hope this will clear your doubt.
Classes are reference types. What that means is that a variable typed to a class:
let someObject = SomeClass()
just contains a pointer to that class's memory, under the hood. The class's contents and data can change without changing the original pointer, because it's just a reference.
Structs, on the other hand, are value types. If you have a variable containing something that is a struct type:
var someStruct = SomeStruct()
the variable itself is actually containing all the struct's data. Changing the struct's internal state actually involves reassigning the variable—so in the example above, something like someStruct.foo = "bar" would actually cause the someStruct variable to be reassigned, as if you'd typed:
someStruct = SomeStruct(foo: "bar", otherStuff: someStruct.otherStuff) // or something of this nature
This is also why you have to declare structs using var if you plan to change anything in them, whereas this isn't so with classes.
As for protocols, they can represent either struct or class types, so if you are dealing with a protocol existential, you can't do operations on it that assume it's a class (unless the protocol is constrained as such).
The Mutating Keyword : 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.
Class is not support 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.

Inout in swift and reference type

I'm trying to understand the difference between value and reference type. And now I want to use function from the apple guide:
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
and if I want to use this is function I will write this code
swapTwoInts{&firstIntStruct, &secondIntStruct}
I understand that we must put in this function reference type, but Int is a value type, therefore we use &.
In another hand, when I try change Int to my class in the swap function, I also must write & before instance of my class.
Why I must do it, if it is the reference already?
Suppose we wrote the hypothetical function you're talking about:
class C {}
func swapTwoC(_ lhs: C, rhs: C) {
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
The immediate problem is that lhs and rhs are immutable. To mutate them, we would need to make mutable copies:
func swapTwoC(_ lhs: C, rhs: C) {
var lhs = lhs; var rhs = rhs
let originalLHS = lhs
lhs = rhs
rhs = originalLHS
}
But now the problem is that we're mutating our copies, and not the original references our caller gave us.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
When you have an inout C, and you pass in &myObject, what you're actually passing in is a reference to your reference to myObject. When the function arguments are copied, what's copied is this "ref to a ref". The function can then use that "ref to a ref" to assign a new value to the reference myObject the caller has
I would like to explain it with example. As #Alexander mentioned, for th function with Int as parameter:
1. Pass by value
It will mutate the copies, and not the original references of caller.
More fundamentally, the issue is that when you pass a reference (to an instance of a class, which we call an object) to a function, the reference itself is copied (it behaves like a value type). If that function changes the value of the reference, it's only mutating it own local copy, as we saw.
You can see that
func swapTwoInts(_ a: Int, _ b: Int) { }
If has changed the values of p and q, where self.x and self.y are unchanged. As this function is passing the values of x and y not their reference.
2. Pass by reference:
func swapTwoInts(_ a: inout Int, _ b: inout Int) { }
It passes the reference of self.x and self.y and that's why you don't have to mutate them again as you did by taking p and q in previous type. Because it will take mutating object with var x and var y.
You can see that, a and b have values of references in logs and changing a and b has changed the self.x and self.y as well because a and b has the same reference( address) of x and y.
So there a few lower level memory components that are at play to make full sense of this.
1) When you create a value or reference type you have a new variable on the stack. That variable is either the actual data in the case of a value type or a pointer to the data in the case of a reference type.
2) When you call a function, it creates a new part of the stack and it creates new variables on the stack (which are let instances in swift) that copy the variable passed in. So for value types it does a deep copy and for reference types it copies the pointer.
So what this means is that when you use inout you are saying, take the memory address of this variable and update the data it contains. So you can either give a value type new data or a reference type a new pointer address and it will change outside of the scope of the swap function. It makes it a var (the same one as what is passed in) instead of let like normal.

Declare overloaded += operator as mutating?

I am overloading (or maybe implementing in this case) the += operator for a class (not a struct!). The operation modifies the state of the left-hand-side instance. I noticed that I can declare the left-hand-side element with let without any errors (and since it is an instance of a class, it's internal state changes with the operation). This of course is undesired, and should result in a compile-time-error. Is there a way to declare the overloaded operator as mutating to the left-hand-side element?
class MyClass {
static func +=(lhs: MyClass, rhs: MyClass) {
lhs.fu(rhs) // fu() changes internal state of lhs
}
}
let a = MyClass()
let b = MyClass()
a += b // this is legal but shouldn't be, since instance 'a' will
// have a different internal state after the concatenation
The let constant in this case is the reference a to the MyClass object that it points to. It prevents you from being able to do this:
let a = MyClass()
a = MyClass() //redefinition not allowed
It does not guarantee anything about the constancy of the members of that object however. Classes/objects exist to model constantly changing data, marking methods as mutating would be a bit tedious, because ultimately that's what they're supposed to do, in general.
You should be using structs in cases where you want controlled mutation.

Why do I have to force a downcast of an array object to a subclass in swift

I have the following -- simplified -- code:
class A {
var x: Int = 9
}
class B: A {
var y: Int = 8
}
class S {
var myList = [A]()
}
//class T: S {
// override var myList = [B]()
//}
class V: S {
func foo() {
let bar = myList[2] as! B
print(bar.y)
}
}
In swift 2.1 I have to use the as! or I get the error message that A is not convertible to B. It seems wrong that I should have to force a conversion to the subclass, but maybe I'm missing something.
The commented out part was my first attempt, but that does not compile either with the message myList with type '[B]' cannot override a property with type '[A]'
In both cases I don't understand the behavior since B is clearly a subclass of A.
Can someone explain why I cannot override the declaration?
Can someone explain why I have to force the downcast?
Thanks!
For point (1), you cannot override stored properties at all, only computed properties. Moreover, even when you override a computed property, you can't give it a different type, as you attempt to do here. And since you can't change the type, it actually makes no sense to override a stored property - what would you override it to? If it was an int in the superclass and an int in the subclass, or an [A] in the the superclass and an [A] in the subclass, then you haven't actually changed anything by overriding it. You can change behavior by overriding a computed property, but obviously not with a stored property, so it makes little sense to do so.
For point (2), you have to force the downcast because you are attempting to access a property - namely, y - that isn't present in the superclass. If you want to access a subclass through a superclass reference, you have to restrict yourself to the interface provided by that superclass. A doesn't have a y property, so trying to access bar.y when bar is of type A makes no sense - you have to downcast it to type B to do that.
In OOP generally, converting upwards is usually easy, since we know from the inheritance structure that B is an A, so converting it that way is simple. But the same is not true in the opposite direction - when B inherits from A, then a B is an A, but an A is not a B. Therefore, when you convert downwards from A to B, you have to do so explicitly, because bad things can happen if the thing you are converting turns out not to be a B at all.
Incidentally, you don't have to force the downcast with as! - you can safely attempt it with as?, for instance:
if let bar = mylist[2] as? B {
print(bar.y)
}
else {
print("not a B!")
}