Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Non-Escapable Types #2304

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Non-Escapable Types #2304

wants to merge 10 commits into from

Conversation

tbkka
Copy link
Contributor

@tbkka tbkka commented Feb 2, 2024

This is the first of two proposals covering this new feature:

It propose an Escapable type marker to indicate that a value of this type can escape the local scope -- by being stored in a global or returned, for example.
This new marker would be implicitly satisfied by all current Swift types to avoid breaking existing code and to reflect the expectation that most types can in fact be freely copied and assigned without limit.
We then add a new ~Escapable type requirement that can be used to selectively remove this capability.
We explain the motivation for such types and the basic capabilities and restrictions on their use.

The companion proposal "Lifetime Dependency Constraints for ~Escapable Values" proposes a set of annotations that selectively modify the constraints of ~Escapable types so they can be used to provide accurate compile-time tracking of values that are inherently subsidiary to some other value (for example, iterators over collections or slices that must not outlive the container to which they refer).

These are part of the BufferView roadmap and are prerequisites for that type.

Briefly, non-escapable types are types that cannot "escape" the local
execution context.  These types can also participate in extended
lifetime dependency constraints.  This enables compile-time lifetime
enforcement for values that contain pointers into other values.  This
makes it possible to implement containers that require no runtime
lifetime management of their iterators or slice objects.

In particular, this is a foundational technology for BufferView.
// Example: Local variable with non-escapable type
func borrowingFunc(_: borrowing NotEscapable) { ... }
func consumingFunc(_: consuming NotEscapable) { ... }
func inoutFunc(_: inout NotEscapable) { ... }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be good to add a case for async functions and async let here, it's barely mentioned in the proposal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll see what I can do about including async examples.

Until then, note that the comments about functions apply to all functions, regardless of whether they are async or not, throwing or not.

Similarly, async let guarantees that the called function will return before the current function completes, so it's safe to pass a ~Escapable value to a function called with async let.

@rjmccall rjmccall added LSG Contains topics under the domain of the Language Steering Group workgroup: blocked This proposal is blocked on some other consideration and removed workgroup: blocked This proposal is blocked on some other consideration labels Apr 1, 2024
proposals/NNNN-non-escapable.md Outdated Show resolved Hide resolved
proposals/NNNN-non-escapable.md Outdated Show resolved Hide resolved
These "lifetime dependency" constraints can also be verified at compile time to ensure that the source of the iterator is not modified and that the iterator specifically does not outlive its source.

**Note**: We are using iterators here to illustrate the issues we are considering.
We are not at this time proposing any changes to Swift's current `Iterator` protocol.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We are not at this time proposing any changes to Swift's current `Iterator` protocol.
We are not at this time proposing any changes to Swift's current `IteratorProtocol` construct.

Comment on lines +247 to +249
struct Wrapper<T: ~Copyable & ~Escapable> { ... }
extension Wrapper: Copyable where T: ~Escapable {}
extension Wrapper: Escapable where T: ~Copyable {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The review notes of SE-0427 imply that all suppressed quasi-protocols need to be explicitly spelled out:

Suggested change
struct Wrapper<T: ~Copyable & ~Escapable> { ... }
extension Wrapper: Copyable where T: ~Escapable {}
extension Wrapper: Escapable where T: ~Copyable {}
struct Wrapper<T: ~Copyable & ~Escapable>: ~Copyable, ~Escapable { ... }
extension Wrapper: Copyable where T: Copyable & ~Escapable {}
extension Wrapper: Escapable where T: ~Copyable & Escapable {}

```

The above declarations all in a single source file will result in a type `Wrapper` that is `Escapable` exactly when `T` is `Escapable` and `Copyable` exactly when `T` is `Copyable`.
To see why, first note that the explicit `extension Wrapper: Escapable` in the same source file implies that the original `struct Wrapper` must be `~Escapable` and similarly for `Copyable`, exactly as if the first line had been
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think it would be desirable to have such inference rules. I would prefer to understand type declarations at a glance; I would not enjoy being forced to solve clever little cross-referencing puzzles to understand the nature of a type.

It is extremely noteworthy for a type not to be copyable or escapable. These suppressions deserve to be explicitly noted directly on the type's primary declaration, not inferred from context hidden elsewhere in the source file.

Now recall from SE-427 that suppressible protocols must be explicitly suppressed on type parameters in extensions.
This means that
```swift
extension Wrapper: Copyable where T: ~Escapable {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per SE-0427, this should be an error; the conditional conformance needs to explicitly declare whether it wants T to be copiable. (I.e., the only legal way to spell the conditional conformance is to use the long form below.)


Similarly,
```swift
extension Wrapper: Escapable where T: ~Copyable {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here; SE-0427 implies that this should be an error.


## Future directions

#### `StorageView` type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### `StorageView` type
#### `Span` family of types


#### `StorageView` type

This proposal is being driven in large part by the needs of the `StorageView` type that has been discussed elsewhere.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This proposal is being driven in large part by the needs of the `StorageView` type that has been discussed elsewhere.
This proposal is being driven in large part by the needs of the `Span` type that has been discussed elsewhere.


In addition, these types will support lifetime-dependency constraints (being tracked in a separate proposal), that allow them to safely hold pointers referring to data stored in other types.

This feature is a key requirement for the proposed `StorageView` type.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This feature is a key requirement for the proposed `StorageView` type.
This feature is a key requirement for the proposed `Span` family of types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LSG Contains topics under the domain of the Language Steering Group
Projects
None yet
5 participants