<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” -> “Declarations” -> “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 &arr and &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=""> var a: Int<br class="">}<br class="">func foo(inout s: S, _ a: inout Int) {<br class=""> a += 1<br class=""> s.a += 1<br class="">}<br class=""><br class="">var s = S(a: 0)<br class="">foo(&s, &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(&arr, b: &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=""> // buffer1: +1<br class=""> </font></div><div class=""><font face="Menlo" class=""> let acopy = a<br class=""> // acopy.buffer = a.buffer (which is buffer1)<br class=""> // buffer1: +2<br class=""> </font></div><div class=""><font face="Menlo" class=""> a = [4, 5, 6]<br class=""> // a changes, but it has value semantics and a.buffer’s reference count is > 1<br class=""> // Therefore a new buffer is created.<br class=""> // a.buffer = buffer2 (new buffer identical to buffer1)<br class=""> // Now:<br class=""> // buffer1: +1<br class=""> // buffer2: +1<br class=""> </font></div><div class=""><font face="Menlo" class=""> print(acopy) // prints buffer1: "[1, 2, 3]"<br class=""><br class=""> b = 99 // b points to address in buffer1 because of call-by-reference optimization<br class=""> // buffer1[2] = 99<br class=""><br class=""> print(a) // prints buffer2: "[4, 5, 6]"<br class=""></font><span style="font-family: Menlo;" class=""> print(acopy) // 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=""> // Now a is returned -> buffer2 is returned and stays alive<br class=""> // acopy not returned -> buffer1’s reference count drops to zero -> it is destroyed<br class="">}</font></div><div class=""><font face="Menlo" class=""><br class="">print(arr) // 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 <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> 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 undefined. It is documented in the Swift book somewhere. <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 <<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a>> 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 <swift-users@swift.org> 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 which the `&` 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 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 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 has returned new values for both `arr` and arr[2]`, both of which get stored back where they came from, but the ordering is significant because 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 “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 longer, I’m forced to conclude that the compiler decided it could optimize the `b` parameter by actually passing a pointer to the Int and 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 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 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>