Skip to content

Commit bbcb22a

Browse files
committed
ABI: Adding or removing copyability both affect ABI
Add discussion about how the abstract property ABI has to be different between noncopyable and copyable properties because we can't generally `get` a noncopyable stored property.
1 parent 258dcf7 commit bbcb22a

File tree

1 file changed

+46
-3
lines changed

1 file changed

+46
-3
lines changed

proposals/NNNN-noncopyable-structs-and-enums.md

+46-3
Original file line numberDiff line numberDiff line change
@@ -951,15 +951,58 @@ For existing Swift code, this proposal is additive.
951951

952952
## Effect on ABI stability
953953

954+
### Adding or removing `@noncopyable` breaks ABI
955+
954956
An existing copyable struct or enum cannot be made `@noncopyable` without
955-
breaking ABI, since existing clients may copy values of the type. However,
956-
an noncopyable type can be made copyable without breaking its ABI.
957+
breaking ABI, since existing clients may copy values of the type.
958+
959+
Ideally, we would allow noncopyable types to become copyable without breaking
960+
ABI; however, we cannot promise this, due to existing implementation choices we
961+
have made in the ABI that cause the copyability of a type to have unavoidable
962+
knock-on effects. In particular, when properties are declared in classes,
963+
protocols, or public non-`@frozen` structs, we define the property's ABI to use
964+
accessors even if the property is stored, with the idea that it should be
965+
possible to change a property's implementation to change it from a stored to
966+
computed property, or vice versa, without breaking ABI.
967+
968+
The accessors used as ABI today are the traditional `get` and `set`
969+
computed accessors, as well as a `_modify` coroutine which can optimize `inout`
970+
operations and projections into stored properties. `_modify` and `set` are
971+
not problematic for noncopyable types. However, `get` behaves like a
972+
function, producing the property's value by returning it like a function would,
973+
and returning requires *consuming* the return value to transfer it to the
974+
caller. This is not possible for noncopyable stored properties, since the
975+
value of the property cannot be copied in order to return a copy without
976+
invalidating the entire containing struct or object.
977+
978+
Therefore, properties of noncopyable type need a different ABI in order to
979+
properly abstract them. In particular, instead of exposing a `get` accessor
980+
through abstract interfaces, they must use a `_read` coroutine, which is the
981+
read-only analog to `_modify`, allowing the implementation to yield a borrow of
982+
the property value in-place instead of returning by value. This allows for
983+
noncopyable stored properties to be exposed while still being abstracted enough
984+
that they can be replaced by a computed implementation, since a `get`-based
985+
implementation could still work underneath the `read` coroutine by evaluating
986+
the getter, yielding a borrow of the returned value, then disposing of the
987+
temporary value.
988+
989+
As such, we cannot simply say that making a noncopyable type copyable is an
990+
ABI-safe change, since doing so will have knock-on effects on the ABI of any
991+
properties of the type. We could potentially provide a "born noncopyable"
992+
attribute to indicate that a copyable type should use the noncopyable ABI
993+
for any properties, as a way to enable the evolution into a copyable type
994+
while preserving existing ABI. However, it also seems unlikely to us that many
995+
types would need to evolve between being copyable or not frequently.
996+
997+
### Adding, removing, or changing `deinit` in a struct or enum
957998

958999
An noncopyable type that is not `@frozen` can add or remove its deinit without
959-
affecting the type's ABI; if frozen, then a deinit cannot be added or removed,
1000+
affecting the type's ABI. If `@frozen`, a deinit cannot be added or removed,
9601001
but the deinit implementation may change (if the deinit is not additionally
9611002
`@inlinable`).
9621003

1004+
### Adding noncopyable fields to classes
1005+
9631006
A class may add fields of noncopyable type without changing ABI.
9641007

9651008
## Effect on API resilience

0 commit comments

Comments
 (0)