This is a RFC on copy-on-write strings [https://github.com/nim-lang/RFCs/issues/221](https://github.com/nim-lang/RFCs/issues/221) (no code or pseudo-code though)
For your own refcounting scheme, as @snej mention, it's easy to do with destructors, see my atomic ref counted type here: [https://github.com/mratsim/weave/blob/9f0c384f/weave/cross_thread_com/flow_events.nim#L173-L201](https://github.com/mratsim/weave/blob/9f0c384f/weave/cross_thread_com/flow_events.nim#L173-L201) type FlowEvent* = object e: EventPtr EventPtr = ptr object refCount: Atomic[int32] # Refcounting is started from 0 and we avoid fetchSub with release semantics # in the common case of only one reference being live. proc `=destroy`*(event: var FlowEvent) = if event.e.isNil: return let count = event.e.refCount.load(moRelaxed) fence(moAcquire) if count == 0: # We have the last reference if not event.e.isNil: if event.e.kind == Iteration: wv_free(event.e.union.iter.singles) # Return memory to the memory pool recycle(event.e) else: discard fetchSub(event.e.refCount, 1, moRelease) event.e = nil proc `=sink`*(dst: var FlowEvent, src: FlowEvent) {.inline.} = # Don't pay for atomic refcounting when compiler can prove there is no ref change `=destroy`(dst) system.`=sink`(dst.e, src.e) proc `=`*(dst: var FlowEvent, src: FlowEvent) {.inline.} = `=destroy`(dst) discard fetchAdd(src.e.refCount, 1, moRelaxed) dst.e = src.e Run To add Copy-On-Write on top you need to change the `=` so that it checks how many reference there are and if there is one `detach`/`copy`, `=sink` and `destroy` can stay as-is.
