# Developing intuition for when values will be copied

**URL:** <https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421>\
**Category:** Using Swift\
**Tags:** performance\
**Created:** [May 1, 2026, 8:23pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421 "2026-05-01T20:23:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![snej](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/snej/32/365_2.png) [@snej](https://forums.swift.org/u/snej)\
**Post date:** [May 1, 2026, 8:23pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421/1 "2026-05-01T20:23:53Z")

</div>

TL;DR: I'm looking for rules of thumb about the circumstances when optimized Swift code will copy a (nontrivial) struct/enum value.

Coming from C++ as I do, I'm used to thinking about the overhead of passing parameters by value vs by reference, or of copying a value vs using a move constructor. In Swift these things tend to be implementation details of the optimizer, but part of my brain still wonders whether I'm doing things efficiently.

I'd like to know if there are rules of thumb for what will cause a struct/enum value to be copied, so I can design appropriately.

Here are some things that I believe to be true:

1. Class and actor instances are of course never copied. You have to explicitly create a new instance. (Same goes for `~Copyable` values, for different reasons.)
2. Tiny types like `Int` and `Double` are passed by value, usually in a register.
3. Small-ish types that fit in "a few" registers, like structs/enums/tuples of a few primitive fields, are passed by value in multiple registers. (I know this is ISA-specific but I think it's true in both x86-64 and ARM.)
4. Bigger types are passed by reference. This is safe because Swift guarantees that a mutable reference never coexists with read-only references. An `inout` argument is modified in place by the callee, without copying.
5. Similarly, `self` is passed by reference to a method, and a `mutating` method modifies its receiver in place.
6. I'm less sure about return values. In a C/C++ ABI small return values are usually returned in one or perhaps "a few" registers, and larger return values have space reserved by the caller, which passes a reference to that space as a hidden parameter. Not sure if Swift does that too. That can result in a copy if the struct exists as a stored value somewhere else and gets returned to the caller. (Unless the compiler is able to inline the function, maybe.)
7. Explicitly assigning a value to another variable copies it (unless the compiler can optimize it away.)
8. Properties with custom setters, and subscripts with setters, seem like the major place where implicit copies happen. If I write `foo.string += "x"`, and `Foo.string` is a property with a custom getter/setter, Swift will call the getter and copy the String, then mutate the string, then call the setter to copy it back. Same thing with `array[6].mutatingMethod()` -- it calls the Array subscript to copy the value, invokes `mutatingMethod()`, then copies the result back.

Is this accurate? Are there more situations to consider?

---

<div class="post-metadata">

**Author:** ![bbrk24](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bbrk24/32/27370_2.png) [@bbrk24](https://forums.swift.org/u/bbrk24)\
**Post date:** [May 1, 2026, 8:35pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421/2 "2026-05-01T20:35:40Z")

</div>

> [@snej](#):
>
> I'm less sure about return values. In a C/C++ ABI small return values are usually returned in one or perhaps "a few" registers, and larger return values have space reserved by the caller, which passes a reference to that space as a hidden parameter. Not sure if Swift does that too. That can result in a copy if the struct exists as a stored value somewhere else and gets returned to the caller. (Unless the compiler is able to inline the function, maybe.)

This document on the calling convention may contain relevant information: [swift/docs/ABI/CallingConvention.rst at main · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/blob/main/docs/ABI/CallingConvention.rst) (and maybe a couple of the other documents in that ABI folder as well)

Without having re-read that recently, I'm pretty sure small values are returned across a couple registers, and larger structs as well as values of unknown size (e.g. `f<T>() -> T`) are returned indirectly as you describe for larger structs in C.

> [@snej](#):
>
> Same thing with `array[6].mutatingMethod()` -- it calls the Array subscript to copy the value, invokes `mutatingMethod()`, then copies the result back.

Some things, such as array index accessors, allow in-place modification. In the past this was achieved by providing a third accessor alongside `get` and `set` called `_modify`, but my understanding is that's being replaced by more well-defined features like borrowing accessors.

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [May 1, 2026, 10:00pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421/3 "2026-05-01T22:00:43Z")

</div>

i find that thinking about procedure calling convention in Swift tends to obscure more than it illuminates. optimized Swift code often looks nothing like the stack diagrams you see in Intro To Systems Programming, what happens in practice is your entire call tree will get flattened into a few giant, heavily inlined slabs with values moving opaquely and fluidly between memory and registers. and this is usually what you want (ease of profiling notwithstanding), as these are the conditions under which Swift code executes most efficiently.

what you want to be thinking about instead is resilience boundaries (“where are the chocolate chips in my inlined brownie?”), whether you’ve configured the right reference counting conventions (`borrowing`/` __shared` versus `consuming`/`__ owned`) along those boundaries, and whether you are mutating (allocated) things that are uniquely referenced.

---

<div class="post-metadata">

**Author:** ![Cyberbeni](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cyberbeni/32/46241_2.png) [@Cyberbeni](https://forums.swift.org/u/Cyberbeni)\
**Post date:** [May 1, 2026, 10:40pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421/4 "2026-05-01T22:40:11Z")

</div>

> [@bbrk24](#):
>
> In the past this was achieved by providing a third accessor alongside `get` and `set` called `_modify`

It's still the case: [swift/stdlib/public/core/Array.swift at 1b00845e5ae3f5600e1e5d87c71e67c5427fbd9f · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/blob/1b00845e5ae3f5600e1e5d87c71e67c5427fbd9f/stdlib/public/core/Array.swift#L766-L772)

---

<div class="post-metadata">

**Author:** ![snej](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/snej/32/365_2.png) [@snej](https://forums.swift.org/u/snej)\
**Post date:** [May 1, 2026, 10:44pm UTC](https://forums.swift.org/t/developing-intuition-for-when-values-will-be-copied/86421/5 "2026-05-01T22:44:21Z")

</div>

Oh right, this is the 'coroutine-based' accessor that's going to become `yielding mutate` once SE-0474 is finished. I forgot to mention that.
