Modify and Yield
Did you know Swift implementation has a _modify
/yield
property accessor?
It modifies the String in place without creating a copy (example). Note this optimizes operations on value types (structs), but has no benefit for reference types (classes and actors) since they are already passed as reference.
_modify vs set
_modify/yield
_modify is a Swift property accessor that provides exclusive, mutable access to a property’s storage location for in-place modifications. Exclusive means that for the full duration of the coroutine, the modify body has exclusive access to the variable.
yield transfers an inout reference to the property’s value, allowing direct modification without creating intermediate copies. Without _modify
, a compound operation would create a copy, modify it, and set the new value. With _modify
, these operations modify the value directly in its storage location.
Coroutine control flow
A coroutine is a function that is able to suspend and resume computation. _modify/yield is an example of that because yield transfers control to the caller and then resumes executing the _modify block (example).
Coroutine behavior
The compiler checks that there is exactly one yield on every execution path inside _modify
. If the code we yielded to throws, the _modify
body terminates immediately (after running any defer
there may be) and control is returned to the caller (example).
Terminates on throw
set vs _modify
If set
and _modify
are both available, _modify
is automatically used for compound assignments or other in-place modifications, while _set
is automatically used for simple assignments (example). If only one (set
or _modify
) is available it will be used for both operations.
set and _modify
The compound assignments that trigger _modify are
- Arithmetic compound operators:
+=
,-=
,*=
,/=
,%=
- Bitwise compound operators:
&=
,|=
,^=
,<<=
,>>=
- For strings/arrays:
+=
,.append()
,.insert()
,.remove()
, and similar mutating methods - For dictionaries/sets: subscript with compound assignment (
+=
),.merge()
, union/intersection operators like.formUnion()
,.formIntersection()
Word of caution
_modify
and yield
were introduced in the pitch Modify Accessors in 2019. As of dec 2024, _modify
still uses an underscore prefix. The pitch author says
Underscored attributes are not source stable and that means you need to deal with the consequences of them not being source stable
But if you still decide to use it, know that it continues to be added in Apple code, and it would be easy to replace.