Non-copyable protocol

Hi,

I have a question ~Copyable for protocols.

Given the following marker protocol:

protocol NonCopyable : ~Copyable, Sendable {
}

the following actor can be defined:

actor NonCopyableActorByProtocol : NonCopyable {
}

and this will happily compile.

However, if I define the following actor:

actor NonCopyableActor : ~Copyable {
}

I’m told an actor cannot be ~Copyable.

Why then would the first version work?

Thanks.

1 Like

Your NonCopyable protocol doesn't mean what you thought.

On a protocol, the : ~Copyable constraint does not mean "must be non-copyable". It means "can be non-copyable" (or equivalently, "doesn't need to be copyable").

As a simple proof, you can conform Int to that protocol, despite Int clearly being a copyable type:

protocol NonCopyable: ~Copyable, Sendable {}

extension Int: NonCoptable {}
4 Likes

Ooooh

Does that mean that anything conforming to a protocol that is not marked ~Copyable must be copyable?

Yes, it's an implied constraint. Both for backwards compatibility (so people don't have to run around adding : Copyable everywhere), and because it's usually what people want, anyway. E.g. In Rust you'll find that many of the traits you write end up needing clone.

A bare protocol P {} has an implicit constraint as if it were written protocol P: Copyable {}. Adding ~Copyable merely relaxes that constraint, it does not impose a new "must be non-copyable" constraint.

4 Likes

Very clear. Thanks!

Happy to help!

For more reading, I'd suggest the SE proposal itself, which clarifies this quite well: swift-evolution/proposals/0427-noncopyable-generics.md at main · swiftlang/swift-evolution · GitHub

3 Likes