> On Nov 4, 2016, at 5:59 AM, Ryan Lovelett via swift-users
> <[email protected]> wrote:
>
> struct Foo {
> init(from buffer: Data) {
> bar = integer(withBytes: Array(buffer[4..<6]))
> baz = integer(withBytes: Array(buffer[6..<8]))
> ...
> }
>
> let d = Data(count: Int(3e+8))
> let f = Foo(from: d)
>
> Did I just make two copies of the `Data`? How would I investigate this
> to understand it?
Do you mean, "did I make two copies of the `Data`, one in a top-level variable
named `d` and the other in a parameter named `buffer`"?
If so, then answer is "Yes, but…"
A value type like `Data` can't really hold variable-sized data like the bytes
in a `Data` object. Instead, the bytes are stored in a separate object, and
`Data` manages that with copy-on-write semantics. In other words, there are two
copies of the `Data` instance itself, but they share a single copy of the bytes
they're storing.
To illustrate more clearly, after this line:
let d = Data(count: Int(3e+8))
You have something like this:
| ...stack frame for top level... |
+-------------------------------+
| Data instance (d) | --------------> |
...3e+8 bytes of data... |
| |
+-------------------------------+
And then once you execute the call on this line:
let f = Foo(from: d)
You have this:
| ...stack frame for top level... |
+-------------------------------+
| Data instance (d) | --------------> |
...3e+8 bytes of data... |
| |
+-------------------------------+
| ...stack frame for Foo(from:) |
^
| Data instance (buffer) |
---------------------------------+
If `Foo(from:)` were to copy `buffer` and then mutate the copy, the bytes would
be copied before the mutation occurred. But since neither `f` nor `buffer` is
mutated in this code (indeed, both are in immutable variables!), that never
happens here.
> I _think_ that if I made it `inout` then it would not make a copy but
> now the data buffer is mutable. I want it to be clear I'm not mutating
> the buffer inside the initializer but I also want to be sure I'm not
> making a copy of the buffer either.
That's implementation-specific. Notionally, an `inout` variable is essentially
passed in by value, modified as a copy, returned to the caller, and then
assigned back to the original value. In some cases that's basically what
actually ends up happening. But Swift tries to optimize `inout` behavior into
directly mutating the original variable, and it's often successful.
--
Brent Royal-Gordon
Architechies
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users