Skip to content

Instantly share code, notes, and snippets.

@atrick
atrick / 2024-10-borrow-accessor-semantics.md
Last active November 8, 2024 00:05
Borrow accessor semantics: introducing @dependentBorrow for C++ interop

Borrow accessor semantics: @dependentBorrow and C++ interop

Copyable property read semantics

We start with a container whose element may be either Copyable or Escapable, which will be determined by the calling context:

struct Container<Element: ~Escapable, ~Copyable>: ~Escapable, ~Copyable {
  let _element: Element
}

Preview of Lifetime Definitions

Preface

Lifetime definitions are an indisputably complicated feature. At least three aspects of the Swift language make the semantics challenging to express syntactically:

  1. Swift lacks first-class references. This leads to a dichotomy between concrete vs. generic lifetimes. Concrete lifetimes imply a required lifetime dependence. Generic lifetimes represent potential lifetime dependence.

  2. Unconditionally nonescapable types have fundamentally different lifetime constraints than conditionally escapable types, but the difference between these two flavors of lifetime dependent types is not syntactically apparent.

@atrick
atrick / 2024-08-property-lifetimes.md
Last active November 5, 2024 19:50
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: