With ~Copyable
and ~Escapable
types, Swift properties can, in theory, be accessed in different ways that affect where the property value can be used. Here we describe four kinds of property access that each have different lifetime semantics. These lifetime semantics generalize to function results and coroutine yields; in this respect, there's no need to distinguish between "properties" and functions. Each kind of lifetime does, however, describe a relationship between the result and some outer value that the result is derived from. For this reason, property access is a helpful conceptual framing. This document suggests possible ways that the semantics could be expressed in the language. Our goal is not for programmers to think in terms of these four kinds of access lifetimes; natural usage of ~Copyable
and ~Escapable
types should lead to common-sense behavior. Instead, this formalization is meant to guide future Swift evolution proposals, which may propose some useful subsets of
The following additional sections have been added to the original pitch.
Normally, lifetime dependence is required when a nonescapable function result depends on an argument to that function. In some rare cases, however, a nonescapable function parameter may depend on another argument to that function. Consider a function with an inout
parameter. The function body may reassign that parameter to a value that depends on another parameter. This is similar in principle to a result dependence.
This pitch is an active brainstorm. It may eventually be converted into an SE proposal.
This proposal introduces a nonescapable, noncopyable UniqueSpan<T>
type. Like Span<T>
, which is also nonescapable, it does not manage the underlying storage. But unlike Span<T>
, it is noncopyable and takes ownership of all the elements within the span, allowing them to be moved, consumed, or replaced.
In some cases, a nonescapable value must be constructed without any object that can stand in as the source of a dependence. Consider extending the standard library Optional
or Result
types to be conditionally escapable:
enum Optional<Wrapped: ~Escapable>: ~Escapable {
case none, some(Wrapped)
}
In some cases, a nonescapable value must be constructed without any object that can stand in as the source of a dependence. Consider extending the standard library Optional
or Result
types to be conditionally escapable:
enum Optional<Wrapped: ~Escapable>: ~Escapable {
case none, some(Wrapped)
}
The current design of lifetimes relies on "value lifetimes" and "conditionally non-escapable types". Values of Escapable
type have no lifetime scope. Values of ~Escapable
type have a single lifetime scope. A nonescapable value cannot live beyond the current scope unless the scope's function interface provides value-based lifetime propagation via @dependsOn
annotations.
E ≡ some T
NE ≡ some T: ~Escapable
Without a lifetime annotation, functions cannot return nonescapable values:
Table of Contents
This proposal adds restrictions on implicit casts to unsafe pointers. It allows implicit casts only when the source value is either "bitwise copyable" or has custom support for unsafe pointer casts. A type is bitwise copyable if copying a value of that type requires nothing more than copying each bit in its representation (i.e. memcpy
). Bitwise copyable types do not require deinitialization. Notably, bitwise copyable types cannot contain object references. Raw pointers are primarily intended for use with bitwise-copyable types because it is extremely difficult and dangerous to work with raw bytes in the presence of object references.
The implicit raw pointer casts that we want to prohibit commonly happen accidentally, without any source-level indication of unsafety. They nonetheless pose a serious safety and security concern. They are a common source of programming mistakes leading to runtime crashes but have no discer
A lifetime-dependent property (or "dependent property") is a struct or class property whose value can only be accessed within an enclosing scope, during which the parent object cannot be deinitialized. A dependent property can provide a lightweight "view" of its parent object's underlying storage through an alternate type. This proposal focuses on the problem of returning the view object as a property of its "container". The author of the view type still bears responsibility for other aspects of safety. The Future Directions sections cover additional features needed to support development of safe view types.
A container data type often needs to provide limited access to its underlying storage to a more general purpose API that consumes the data but is otherwise independent of the data type. In Swift, this is typically done by having the container provide a "slice" that conforms to the Collection protocol. Since slices depend on their container's