SE-0437: Generalizing standard library primitives for non-copyable types

This proposal updates withExtendedLifetime. That gives us an opportunity to fix two pain points the programmers have been complaining about.

  1. In most cases, the syntax that we recommend is:
    defer { withExtendedLifetime(obj) {} }.
    This usage was not anticipated when the API was designed and it's proving to be very confusing. Understandably, people are unsure whether the operation has any effect when an empty closure is passed. We should add the natural non-closure-taking form:
public func extendLifetime<T: ~Copyable>(_ x: borrowing T) {
  Builtin.fixLifetime(x)
}

And begin recommending this API instead in most cases. For example:

  defer { extendLifetime(obj) }
  weak var ref = obj
  _ = ref!

Note that we don't want to introduce a new name for this API, which is just a simpler form of withExtendedLifetime. we only want to drop the with prefix in the common case of no nested closure.

  1. The current API is incompatible with concurrency. Programmers have been asking us to fix this since concurrency was first introduced. We should add an async overload:
public func withExtendedLifetime<T: ~Copyable, Result: ~Copyable>(
  _ x: borrowing T,
  _ body: () async throws -> Result
) async rethrows -> Result {
  defer { extendLifetime(x) }
  return try await body()
}
11 Likes