> On Nov 4, 2016, at 5:59 AM, Ryan Lovelett via swift-users 
> <swift-users@swift.org> 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
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to