What is ~Copyable for?

That’s not a use-case in the sense I mean it. What’s an example of a problem where you “need a deinit” but using a class is inappropriate?

Not sure why you see the infectious nature is a downside -- it's sort of the whole point.

It’s the whole point up to a point. At some point I want to be able to embed my resource manager in something copyable and then explicitly determine how that something should deal with it. In C++ (if we must go there) a unique_ptr member doesn’t automatically make everything it is a part of non-copyable all the way to the aggregation root.

Not every resource lifetime is scoped to the dynamic extent of a single function call. You might want to initialize a resource in one function and "hand it off" somewhere else, or store it somewhere.

“Might want to” is not what I’m looking for here. I want to understand what specific real world use-cases are best addressed using ~Copyable and how to describe them generally. Ultimately I also want to understand why having this feature with its attendant complexity is better than not having it. For example, you can handle the pattern above without having linear types; you just have to give up being restricted from copying the resource at compile-time.

It’s awkward, but you can even get some runtime checking:

/// An instance of `T` whose value can be used once.
class Linear<T> {
  /// The instance, or `nil` if it has been used
  private var x: T?

  /// An instance with value `x`.
  public init(_ x: T) { self.x = x }

  /// Returns the value, making it unavailable for further use.
  public mutating func consume() -> T {
    precondition(x != nil, "\(T.self) was already used.")
    defer { x = nil }
    return x!
  }
}

Of course I realize there are low-level applications where the overhead of allocating a class is inappropriate; if I thought runtime checking was valuable enough to use the above in testing I’d replace it with a structthat does no runtime check for release builds.

With regard to “relying on a sufficiently smart optimizer” I agree with you 100%. But there are many extra copies that should never existed in the first place and thus shouldn’t depend on the optimizer for elimination. “You can’t count on Swift not to generate arbitrary copies” ought to instead be “these are the only scenarios where copies are created.” I still believe borrowing should have been made the default despite the extremely marginal semantic differences it introduces.

3 Likes