Manually implementing `copy`?

The Copyable protocol can currently only have an implicit copy implementation. Could we make it possible for someone to write their own copy implementation?

struct MyNotCopyableType: ~Copyable {
  private var id: Int
extension MyNotCopyableType: Copyable {
  func copy() -> MyNotCopyableType {
    MyNotCopyableType(id: id + 1)

Just curious, because that would make something like C++ copy constructors possible


Could you please clarify what you want to achieve? To my eyes you just implemented your own copy function, just remove the conformance to Copyable in the extension and you're good to go.

I'm just curious if it's possible to make a custom conformance to Copyable. I don't have a specific use-case in mind.

1 Like

Oh, you meant you want to override the behaviour of the implicit copy operation?
I'm not sure if having such construct in the language is a good idea.

Yeah, I think there are some nice things we could do with this.

Since ~Copyable types can include a deinitialiser, I suppose you could theoretically implement your own reference-counting system.

Why would you want to do that? One reason is that, if copy and deinit were isolated to a global actor, reference counting could be performed using simple non-atomic integer operations.

For cases where copies/destroys usually occur in the same statically-global-actor-isolated context, this would likely be cheaper than normal reference counting. Cross-actor copies and destroys would incur a hop, which is likely more expensive than atomic operations, but you would have the choice which usecases to prioritise.

EDIT: The way I'm thinking of this, copies would require the explicit copy x operation. I guess you may be able to do it even today if you were content with using a function instead of the built-in keyword.

EDIT2: Very quick sketch

Now that we have structs with deinits, you can kind of do it and values get released/freed automatically. We're so close! But... it's still not really usable because the "pointer" type (RefCounted<T>) is non-copyable and cannot be made copyable. Also the global actor constraint on the copy function would need to be propagated to any data types which contain one of these references.

We're not a million miles away though. I think it's pretty cool. Obviously it would be easier if you didn't care about being fancy with global actor isolation and just wanted to interop with some existing thread-safe refcounting system.