This is probably a bit wild with a lot of edge cases, but I'm going to suggest it anyway because I fear those ~Copyable
markers are going to be quite viral in many places and I'd like to reduce the need for them. It goes beyond the scope of the current proposal, trying to anticipate future needs.
I suppose we could make those anti-Copyable
markers go away (for types) in many instances by redefining things like this:
struct Thing { var i: Int } // not Copyable by itself
// but this is implicitly inferred because all the members are copyable:
extension Thing: Copyable {}
And if you have this:
struct Thing<Wrapped> { var w: Wrapped } // not Copyable by itself
// but this is implicitly inferred based on the types of the members:
extension Thing: Copyable where Wrapped: Copyable { }
And if you aren't satisfied by the implicit inference (maybe you're writing a copy-on-write container of some sort), you can just write the conformance differently to suppress the inferred one:
struct COWThing<Wrapped> {
var s: Storage<Wrapped>
mutating func replace(with new: Wrapped) {
if isKnownUniquelyReferenced(&s) {
s.content = new
} else if Wrapped is Copyable {
s = Storage(s.content, new) // copy here!
} else {
fatalError("Logic error: should always be uniquely referenced when Wrapped is not Copyable.")
}
}
}
// manual conformance to Copyable: limits it to when Wrapped is copyable
// to only allow copies when copy-on-write is implementable:
extension COWThing: Copyable where Wrapped: Copyable { }
// the manual conformance replaces the one that would be inferred.
And for types which are never copyable, you can provide a deinit
to make them unconditionally uncopyable:
struct FileHandle {
var handle: Int
deinit { ... } // supress Copyable
}
No need for ~Copyable
to define all these types.
Of course, you'll still need ~Copyable
(or some equivalent) for generic functions. But maybe not all of them. For instance we now have this:
func test<T>(_ t: T) -> T
where T: Copyable // this line is inferred
{
return t
}
But I suppose we could make borrow
and consume
automatically remove this inference, and thus reduce the need for ~Copyable
:
func test<T>(_ t: consume T) -> T
// no inference that T is Copyable because of `consume`
{
return t
}
Note that while borrow
and consume
suppress the inference, you can still write it explicitly if needed:
func test<T: Copyable>(_ t: borrow T) -> T {
globalVariable = t // copy here!
return t
}
This is probably going to break existing code that makes use of borrow
and consume
though. Has this feature shipped yet? Or can it be changed for Swift 6?
There's obviously going to be some situations where ~Copyable
is still needed. But not having to write ~Copyable
in most places would make it much better for working with non-copyable types.