Copyable Types
Swift types can be categorized by how they handle copying, which in turn is decided by the type conformance to two marker protocols:
- Copyable: is the ownership of the value type copied or transferred?
- BitwiseCopyable: can the type be copied with a direct memory operation? (like memcpy)
A new syntax was added to explicitly indicate non-conformance to these protocols: a ~
prefix. Therefore, a type can also conform to ~Copyable
(“noncopiable”) and ~BitwiseCopyable
.
Noncopiable Types
A noncopyable type is a struct
or enum
where ownership can be transferred.
- Using a noncopyable type after ownership has been transferred is a compiler error.
- To mark a type as noncopyable, declare it with
~Copyable
.
Noncopiable types
- can’t be global variables
- can’t conform to any protocols except
Sendable
- can’t appear as properties of other than noncopyable types
- don’t support generics at this time (thus, optionals and arrays of noncopyable are not allowed)
- can have
deinit
, which run automatically at the end of the unique instance’s lifetime (unless explicitly suppressed withdiscard self
in aconsuming
method)
Other limitations
- Changing
Copyable
in a library will break the ABI. - Sometimes an error appears on the original definition of the type, not on the wrong use of it.
- Actors and classes cannot be declared as noncopyable, but they can contain noncopyable stored properties.
Implementation detail: to implement noncopyable types Apple added Copyable conformance to all Swift types. When you conform to ~Copyable
you are overriding this conformance.
The documentation says:
All existing first-class types (excluding nonescaping closures) implicitly satisfy this constraint.In programming language theory, a first-class type or value generally refers to entities that can be:
- Assigned to variables
- Passed as arguments to functions
- Returned from functions
- Stored in data structures
- Actors
- Basic value types (Int, String, etc)
- Classes
- Enums and structs –unless they have noncopyable stored properties
- Functions (except nonescaping closures)
- Protocols
Copyable
language type so I guess all are.
Function signature
Noncopyable parameters can be
borrowing
: read only accessinout
: mutation allowedconsuming
: caller can’t use it after calling the function- Example
Methods of noncopyable types:
mutating
methods can change the instance- non mutating methods can be
borrowing
(default): allow read accessconsuming
: invalidate the instance once they complete- Example
Pattern Matching
0432 refined the behavior of noncopyable structs and enums presented in 0390. I’m using switch
in examples, but the following applies to pattern matching performed with switch
, if
, while
, for
, and guard
.
Pattern matching a noncopyable can either borrow or consume:
- Temporary values (like a function result) are consumed.
- Variables and stored properties are borrowed, but you may consume them adding
consume
. - Example
Example of switch borrow/consume
Variables and stored properties are borrowed by default.
But you may consume them if you add consume
.
Temporary values (like a function result) are consumed by default.
Restrictions when switching over noncopyable types:
- The
switch
cannot consume the value during pattern matching where
clauses cannot consume pattern bindings- The value’s ownership can only be transferred once the final match is chosen
- Example
Example of switch restrictions
Two things:
- There is a false warning on
handle
: it needs to be avar
in order to compile. - I’m wrapping the example on a function because global noncopyable are not allowed.
Bitwise Copyable
A bitwise-copyable type is one that can be safely copied using direct memory operations (like memcpy
), and requires no special cleanup when destroyed.
Examples of bitwise-copyable types are pointers, ints, floats, structs with bitwise-copyable fields. See the whole list in SE-0426 Appendix: Standard library conformers.
To mark a type as bitwise-copyable, conform it to the empty BitwiseCopyable protocol. The only condition is that all stored properties must be BitwiseCopyable
. Example.
Example of BitwiseCopyable types
Automatic conformance to BitwiseCopyable
is inferred
- for public enums that are
@frozen
- for non public types when:
- All stored properties are bitwise-copyable
- The type is defined within the current module
- The type is not marked with
~BitwiseCopyable
- Example
Generics types can be conditionally bitwise-copyable. Example
Limitations of bitwise-copyable types:
- Cannot be applied to global variables
- Cannot extend the protocol
- Cannot be used with dynamic type casting (
as?
,is
) - Example
Examples of BitwiseCopyable limitations
ABI compatibility of a library will break (you will have to recompile its clients) if you add and then remove BitwiseCopyable
. Same as with ~Copyable
. Example.
Not sure if the type will remain bitwise-copyable? better opt-out to preserve ABI compatibility.
References
For more details, see