<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Sorry for the terse answer, I’ll try to expand a bit on my reasoning here.</div><div class=""><br class=""></div><div class="">In the Swift book, in “Language Reference” -&gt; “Declarations” -&gt; “In-Out Parameters”, it says:</div><div class="">“You can’t pass the same argument to multiple in-out parameters because the order in which the copies are written back is not well defined”.</div><div class=""><br class=""></div><div class="">Now, I am not 100% sure whether &amp;arr and &amp;arr[2] can be considered the same argument, but I would argue that they can because arr contains arr[2].</div><div class="">And because passing the same argument to two inout parameters is not allowed, the compiler can use an optimization like call-by-reference.</div><div class=""><br class=""></div><div class="">Here is an example, where the compiler assumes the arguments are not the same, and therefore uses call-by-reference instead of copy-in-copy-out:</div><div class=""><font face="Menlo" class="">struct S {<br class="">&nbsp; &nbsp; var a: Int<br class="">}<br class="">func foo(inout s: S, _ a: inout Int) {<br class="">&nbsp; &nbsp; a += 1<br class="">&nbsp; &nbsp; s.a += 1<br class="">}<br class=""><br class="">var s = S(a: 0)<br class="">foo(&amp;s, &amp;s.a)<br class="">print(s) // prints 2</font></div><div class=""><br class=""></div><div class="">So, to come back to the original example. Here is what I think is happening.</div><div class="">Even though arrays are value types, internally they use a reference-counted buffer. In order to mutate the array, the internal buffer must be uniquely referenced. If it is not, a new identical buffer is created.</div><div class=""><br class=""></div><div class="">So I’m going to follow the life of these internal buffers in the sample code:</div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><span style="font-family: Menlo;" class="">var arr = [1,2,3]</span><br style="font-family: Menlo;" class=""><span style="font-family: Menlo;" class="">// arr.buffer = buffer1 (new buffer)</span><br style="font-family: Menlo;" class=""><span style="font-family: Menlo;" class="">// buffer1’s reference count: +1</span><br style="font-family: Menlo;" class=""><br style="font-family: Menlo;" class=""><span style="font-family: Menlo;" class="">foo(&amp;arr, b: &amp;arr[2])</span><br style="font-family: Menlo;" class=""></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">func foo(inout a: [Int], inout b: Int) {<br class="">&nbsp; &nbsp; // buffer1: +1<br class="">&nbsp; &nbsp;&nbsp;</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; let acopy = a<br class="">&nbsp; &nbsp; // acopy.buffer = a.buffer (which is buffer1)<br class="">&nbsp; &nbsp; // buffer1: +2<br class="">&nbsp; &nbsp;&nbsp;</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; a = [4, 5, 6]<br class="">&nbsp; &nbsp; // a changes, but it has value semantics and a.buffer’s reference count is &gt; 1<br class="">&nbsp; &nbsp; // Therefore a new buffer is created.<br class="">&nbsp; &nbsp; // a.buffer = buffer2 (new buffer identical to buffer1)<br class="">&nbsp; &nbsp; // Now:<br class="">&nbsp; &nbsp; // buffer1: +1<br class="">&nbsp; &nbsp; // buffer2: +1<br class="">&nbsp; &nbsp;&nbsp;</font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; print(acopy) &nbsp;// prints buffer1: "[1, 2, 3]"<br class=""><br class="">&nbsp; &nbsp; b = 99 &nbsp;// b points to address in buffer1 because of call-by-reference optimization<br class="">&nbsp; &nbsp; // buffer1[2] = 99<br class=""><br class="">&nbsp; &nbsp; print(a) &nbsp; &nbsp; &nbsp;// prints buffer2: "[4, 5, 6]"<br class=""></font><span style="font-family: Menlo;" class="">&nbsp; &nbsp; print(acopy) &nbsp;// prints buffer1: "[1, 2, 99]"</span><br style="font-family: Menlo;" class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">&nbsp; &nbsp; // Now a is returned -&gt; buffer2 is returned and stays alive<br class="">&nbsp; &nbsp; // acopy not returned -&gt; buffer1’s reference count drops to zero -&gt; it is destroyed<br class="">}</font></div><div class=""><font face="Menlo" class=""><br class="">print(arr) &nbsp;// prints buffer2: "[4, 5, 6]"</font></div><div class=""><br class=""></div><div class="">I hope this helps and that I haven’t made any mistake 😊</div><div class=""><br class=""></div><div class="">Loïc</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class="">On Jun 11, 2016, at 10:52 PM, Loïc Lecrenier via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:<br class=""><br class="">Hi,<br class=""><br class="">I think what you said is correct. However, it is not a bug. We can't pass two inout arguments that alias each other because then the behaviour is&nbsp;undefined. It is documented in the Swift book somewhere.&nbsp;<br class=""><br class="">Loïc<br class=""><br class="">Sent from my iPad<br class=""><br class="">On Jun 11, 2016, at 10:36 PM, Jens Alfke via swift-users &lt;<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>&gt; wrote:<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">On Jun 11, 2016, at 11:57 AM, David Sweeris via swift-users &lt;swift-users@swift.org&gt; wrote:<br class=""><br class="">You can’t pass a `let` as an `inout` argument. I’d guess that’s what’s happening is the `arr[2]` part is creating a temporary var to&nbsp;which the `&amp;` part then provides a reference.<br class=""></blockquote><br class="">But `arr` is a var, not a let.<br class=""><br class=""><blockquote type="cite" class="">`b` is then dutifully modified in the function, but there’s no mechanism for copying it back into `arr` when `foo` returns<br class=""></blockquote><br class="">No, it gets copied back using subscript assignment. Remember, `inout` isn’t really passing the address of the parameter (although the optimizer&nbsp;may reduce it to that.) It’s literally in-and-out: the caller passes the original value, the function returns the new value, the caller then stores the&nbsp;new value where the old value came from.<br class=""><br class="">I am not a Swift guru, but I think the problem in this example is that there’s a sort of race condition in that last post-return stage: the function&nbsp;has returned new values for both `arr` and arr[2]`, both of which get stored back where they came from, but&nbsp;the ordering is significant&nbsp;because&nbsp;arr[2] will have a different value depending on which of those assignments happens first.<br class=""><br class="">This smells like those C bugs where the result of an expression depends on the order in which subexpressions are evaluated — something like&nbsp;“x = i + (i++)”. The C standard formally declares this as undefined behavior.<br class=""><br class="">The part I’m still confused by is how `acopy` got modified within the `foo` function, since it’s declared as `let`. After staring at this for a while&nbsp;longer, I’m forced to conclude that the compiler decided it&nbsp;could&nbsp;optimize the `b` parameter by actually passing a pointer to the Int and&nbsp;modifying it directly, and that this has the side effect of modifying the Array object that `acopy` is pointing to, even though it’s supposed to be&nbsp;immutable.<br class=""><br class="">In other words, this looks like a compiler bug. I can reproduce it with Swift 2.2 (which is what my `swift` CLI tool says it is, even though I have&nbsp;Xcode 7.3.1 and I thought that was Swift 2.3?)<br class=""><br class="">—Jens<br class=""></blockquote><blockquote type="cite" class="">_______________________________________________<br class="">swift-users mailing list<br class="">swift-users@swift.org<br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></blockquote>_______________________________________________<br class="">swift-users mailing list<br class="">swift-users@swift.org<br class="">https://lists.swift.org/mailman/listinfo/swift-users<br class=""></blockquote><br class=""></body></html>