I started learning c++ and now I am wondering if I can do some things in Swift as well.
I never actually thought about what happens when we pass a variable as an argument to a function in Swift.
Let's use a variable of type string
for examples.
In c++ I can pass an argument to a function either by making a copy of it, or by passing a reference/pointer.
void foo(string s)
or void foo (string& s)
;
In the 1st case the copy of my original variable will be created, and foo will receive a copy. In the 2nd case, I basically pass an address of the variable in memory without creating a copy.
Now in Swift I know that I can declare an argument to a function to be inout, which means I can modify the original object.
1) func foo(s:String)
...
2) func testPassingByReference(s: inout String)
...
I made an extension to String to print the address of the object:
extension String {
func address() -> String {
return String(format: "%p", self);
}
}
The result was not that I expected to see.
var str = "Hello world"
print(str.address())
0x7fd6c9e04ef0
func testPassingByValue(s: String) {
print("he address of s is: \(s.address())")
}
func testPassingByReference(s: inout String) {
print("he address of s is: \(s.address())")
}
testPassingByValue(s: str)
0x7fd6c9e05270
testPassingByReference(s: &str)
0x7fd6c9e7caf0
I understand why the address is different when we pass an argument by value, but it's not what I expected to see when we pass an argument as an inout parameter.
Apple developer website says that
In Swift, Array, String, and Dictionary are all value types.
So the question is, is there any way to avoid copying objects that we pass to functions (I can have a pretty big array or a dictionary) or Swift doesn't allow us do such things?
Copying arrays and strings is cheap (almost free) as long as you don't modify it. Swift implements copy-on-write for these collections in the stdlib. This isn't a language-level feature; it's actually implemented explicitly for arrays and strings (and some other types). So you can have many copies of a large array that all share the same backing storage.
inout
is not the same thing as "by reference." It is literally "in-out." The value is copied in at the start of the function, and then copied back to the original location at the end.
Swift's approach tends to be performant for common uses, but Swift doesn't make strong performance promises like C++ does. (That said, this allows Swift to be faster in some cases than C++ could be, because Swift isn't as restricted in its choice of data structures.) As a general rule, I find it very difficult to reason about the likely performance of arbitrary Swift code. It's easy to reason about the worst-case performance (just assume copies always happen), but it's hard to know for certain when a copy will be avoided.
Even though inout
parameters modify the variable that was used as an input parameter to the function, they don't exactly work like by reference in other languages. The behaviour in Swift
is called copy-in copy-out or call by value result. It means that when you use an inout
parameter, at the time of the function call, its value is copied and inside the function, a local copy of the variable is modified. At the time of the functions return, it overwrites the value at the inout
parameters original memory location with the modified copy value.
You are printing the address of the variable inside the function, hence you are actually printing the location of the copied value. Try printing after the function returned and you will see that you are printing the original location with the modified value.
For more information, see the In-Out parameters part of the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With