Essentially what I want is a temporary alias for a class property to improve readability.
I'm in the situation described by the following code and I can't see a straightforward solution. What I want to avoid is y
being copied on mutation and then copied back.
Renaming y
would reduce the readability of the actual algorithm a lot.
Is the Swift compiler smart enough to not actually allocate new memory and how would I be able to know that?
If not, how to prevent copying?
class myClass {
var propertyWithLongDescriptiveName: [Float]
func foo() {
var y = propertyWithLongDescriptiveName
// mutate y with formulas where y corresponds to a `y` from some paper
// ...
propertyWithLongDescriptiveName = y
}
// ...
}
struct Array
is a value types in Swift, which means that they are always
copied when assigned to another variable. However, each struct Array
contains pointers (not visible in the public interface) to the actual
element storage. Therefore after
var a = [1, 2, 3, 4]
var b = a
both a
and b
are (formally independent) values, but with pointers to the same element storage.
Only when one of them is mutated, a copy of the element storage is made.
This is called "copy on write" and for example explained in
So after
b[0] = 17
a
and b
are values with pointers to different (independent) element storage.
Further mutation of b
does not copy the element storage again
(unless b
is copied to another variable). Finally, if you assign
the value back
a = b
the old element storage of a
is released, and both values are pointers to the same storage again.
Therefore in your example:
var y = propertyWithLongDescriptiveName
// ... mutate y ...
propertyWithLongDescriptiveName = y
a copy of the element storage is made exactly once (assuming
that you don't copy y
to an additional variable).
If the array size does not change then a possible approach could be
var propertyWithLongDescriptiveName = [1.0, 2.0, 3.0, 4.0]
propertyWithLongDescriptiveName.withUnsafeMutableBufferPointer { y in
// ... mutate y ...
y[0] = 13
}
print(propertyWithLongDescriptiveName) // [13.0, 2.0, 3.0, 4.0]
withUnsafeMutableBufferPointer()
calls the closure with an
UnsafeMutableBufferPointer
to the element storage.
A UnsafeMutableBufferPointer
is a RandomAccessCollection
and
therefore offers an array-like interface.
No, the Swift compiler is not that smart. All you need is a small test to see what it does:
class MyClass {
var propertyWithLongDescriptiveName: [Float] = [1,2]
func foo() {
var y = propertyWithLongDescriptiveName
y[0] = 3 // copied an mutated
print(y) // [3,2]
print(propertyWithLongDescriptiveName) // [1,2]
}
}
let mc = MyClass()
mc.foo()
You have 2 optons:
propertyWithLongDescriptiveName
to NSMutableArray
, which is a reference typeIf 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