You cannot do these things easily currently since the assignment operator cannot be overloaded. There are ways around it, you can "fix" the broken builtin assignment with a TR macro, but since TR macros MUST not change semantics (you can disable them on a global level and code shall continue to work!) this is a bad idea.
type refCounted[T] =
val: T
refs: int
proc `v=`(var x:refCounted[T], var y:refCounted[T]) =
inc(y.refs)
dec(x.refs)
if x.refs <= 0: destroy(x.val)
x.val = y.val
# use let so x and y cannot be assigned
let x, y = refCounted[string]
# instead use x.v to assign and manage refs properly.
x.v = y
using "let" would make sure all assignments happen through a blessed method (such as the ".v" assignment I defined above).
But to actually make it work, I would need to decrease reference on going-out-of-scope (as there a way to do that? maybe a python "with" style enter exit macro?).
And to make it easy to work with, there would need to be a way to pre- "incref" an argument before it is passed as an argument, and "decref" it after the function call return. I can probably write a macro that rewrites every function call with a refCounted arg so that it increfs() on the way in, decrefs() on the way out; or maybe have that macro on the callees instead.
Guess I'll have to try the different approaches and see what works and how efficiently.