@ Martin R pointed me to the aforementioned thread and, in particular, comment No. 16 made by Chris Lattner (Swift mastermind), which helped me understand “ignorance”. Thanks man!
Consider this code:
private var someString: String { get { print("Inside getter") return "Some string" } set { print("Inside setter") } } private func someFunc(inout stringArg: String) { let funcName = "`someFunc()\'" print("Inside " + funcName) let someDontMatter0 = 42, someDontMatter1 = 24 print(stringArg) // sets temporary, not the original one. Hence, no calls to setter stringArg = "Some other string" stringArg = "No matter what string" print("These \(someDontMatter0) and \(someDontMatter1)") print("Leaving " + funcName) // when callee returns, calls the setter with "No matter what // string" as a `newValue' } // implicitly creates temporary initialised with `someString' value // getting from `someString getter. someFunc(&someString)
For someone from a C ++ background, it might seem that the output should look something like this:
Inside `someFunc () '
Inside the recipient
Some line
Internal setter
These 42 and 24
Exit from `someFunc () '
If the actual conclusion is as follows:
Inside the recipient
Inside `someFunc () '
Some line
These 42 and 24
Exit from `someFunc () '
Internal setter
Cool, right?
This anti-intuitive behavior for someone with a C ++ background is the result of a more fundamental logic that underlies many aspects of Swift. As you can see from Chris’s comment, the general Swift compiler way associated with inout properties is to create a temporary object on the stack to keep the original value there (hence calling getter).
So, when you manipulate your inout parameter, you are dealing with a temporary object (with the initial value that you passed to the function), but not with the original one (for me personally this is a bit vague. But well, you can handle it). And finally:
When the called party returns, the caller is activated to copy the value to the place
So, if you change the code a bit:
private var someString: String { get { print("Inside getter") return "Some string" } set { print("Inside setter") } } private func someFunc(inout stringArg: String) {
the output will be:
Inside the recipient
Internal setter
The same applies to saved properties:
private func someFunc() { var someString = "Some string" { willSet { print("Inside \'willSet\' with \'newValue\': \(newValue)") } didSet { print("Inside \'didSet\' with \'oldValue\': \(oldValue)") } } func someOtherFunc(inout stringArg: String) { print("Inside `someOtherFunc()\'") stringArg = "First string" stringArg = "Second string" print("Before leaving the function") } someOtherFunc(&someString) } someFunc()
Output:
Inside `someOtherFunc () '
Before leaving a function
Inside 'willSet' with 'newValue': second line
Inside 'didSet' with 'oldValue': some string
From Chris's answer:
It also ensures that the getter / setter of the property passed inout will have its getter and setter once no matter what the caller does (this is important if the accessories have side effects or roads)
OK, but what if some method that in some cases accepts the inout parameter does not change it (does not call setter or does not change this temporary variable, you name it)? Also, what if I conceived some important logic of my computed variable getter and setter and came across these specific circumstances (just imagine that I open and close files inside getter / setter)? Getters and setters will be called when they are better off.
I would really like to see Chris answer in one form or another in Apple's final Swift 2.0 programming guide.