Skip to content

Instantly share code, notes, and snippets.

@atrick
atrick / 2024-08-property-lifetimes.md
Last active September 15, 2024 18:40
Property lifetimes

Property lifetimes

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

@atrick
atrick / 2024-08-abstract-projection.md
Last active September 2, 2024 02:15
Abstract projection

Abstract Projection

Aug 2024

Concrete projection

Swift member access has projection semantics. Consider this Project wrapper, which stores its wrapped value inline as a stored property.

struct Project<T: ~Copyable>: ~Copyable {
  let value: T
}
@atrick
atrick / 2024-05-lifedep-update.md
Last active May 28, 2024 18:18
[Update] Compile-time Lifetime Dependency Annotations

Update to Compile-time Lifetime Dependency Annotations

The following additional sections have been added to the original pitch.

Additions to Proposed solutions

Dependent parameters

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.

UniqueSpan

This pitch is an active brainstorm. It may eventually be converted into an SE proposal.

Introduction

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.

Motivation

@atrick
atrick / 2024-04-indefinite-lifetimes.md
Last active April 25, 2024 21:09
Indefinite lifetimes

Indefinite lifetimes

Immortal lifetimes

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)
}
@atrick
atrick / 2024-04-bitwisecopyable-dependence.md
Last active April 23, 2024 15:49
Using the `@_unsafeNonescapableResult` function attribute

Using the @_unsafeNonescapableResult function attribute

Indeterminate lifetimes

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)
}
@atrick
atrick / 2024-generic-lifetimes.md
Last active February 29, 2024 00:34
Lifetime dependence with generic types

Lifetime dependence with generic types

Conditionally nonescapable types

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:

@atrick
atrick / 2023-implicit-raw-bitwise.md
Last active February 22, 2023 22:38
Constrain implicit raw pointer conversion to bitwise-copyable values

Constrain implicit raw pointer conversion to bitwise-copyable values

Introduction

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

@atrick
atrick / 2022-12-dependent-properties.md
Last active April 3, 2023 21:52
Dependent properties

Lifetime-dependent properties

Introduction

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.

Motivation

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