If i run the following code in XCode 12 playground (Swift 5.3) I get the same result from two listings:
import Foundation
var dict = NSMutableDictionary()
dict["x"] = 42
func stuff(_ d: inout NSMutableDictionary) {
d["x"] = 75
}
stuff(&dict)
dump(dict) // x is 75
the other:
import Foundation
var dict = NSMutableDictionary()
dict["x"] = 42
func stuff(_ d: NSMutableDictionary) {
d["x"] = 75
}
stuff(dict)
dump(dict) // x is 75 still
As per the documentation here, the second listing should give me an error: https://docs.swift.org/swift-book/LanguageGuide/Functions.html
But it works anyway.
Is this because the enforcement of these in-out rules is constrained to Swift only types, and Cocoa types are exempt?
This works not because Cocoa types are exempt, but because
NSMutableDictionaryis aclass(as opposed to astruct), and theinoutdoes not refer to what you might be thinking.Unfortunately, the documentation you link to (and the more in-depth documentation on
inoutparameters it links to) doesn't make it clear what "value" really means:The following statement hints at it a little, but could be clearer:
The "value" the documentation describes is the variable being passed as
inout. For value types (structs), this is meaningful because every variable holding a value of those types effectively holds a copy of that value.Passing a
structto a function normally copies the value into a new local variable (new variable = copy), whereas you can imagineinoutgiving you direct access to the original variable (no new variable).What's not described is that the effect is identical for classes, which behave differently.
Passing a
classto a function also copies the variable into a new local variable, but the copy isn't meaningful — both variables hold the same thing: a reference to the object itself in memory. Copying in that sense doesn't do anything special, and you can modify the object from inside of the function the same way you could from outside.inoutfor classes behaves the same way as forstructs: it passes the original variable in by reference. This has no bearing on the majority of the operations you'd want to perform on the object anyway (though it does allow you to make the variable point to a different object from within the function):