Hi, I've been playing around with a bit with smart pointers and think I found a nice technique. Sometimes you get a resource from a C function that you have to free later, and it would be nice if Nim could take care of that automatically.
Basically, my smart pointer is an object that hides the unmanaged ptr pointer. You create ref SmartPtr[T] references and pass them around as you like, and if the smart pointer is no longer referenced, nim eventually garbage collects it. I then use a finalizer to free the unmanaged memory (as required by the C API). Basically:
type
Root {.pure, inheritable.} = object
SmartPtr[T] = object of Root
pointer: ptr T
TBaseObject {.pure, inheritable.} = object
BaseObject = ref SmartPtr[TBaseObject]
TWidget = object of TBaseObject
Widget = ref SmartPtr[TWidget]
#...
Here I used the convention that the naked "structs" are called TSomething, and the types you actually use have nice names without T.
Then I defined wrap and unwrap procs to convert between ptr TSomething <-> Something = ref SmartPtr[TSomething]. I made them converters so it works automatically in most places.
proc woof(w: ptr TWidget) =
echo "C function woof called"
I can call it with either a Widget (recommended) or a ptr TWidget. I don't have to wrap the function. If a C function returns a pointer to be managed, you can write a tiny wrapper function:
# C function
proc get_widget_pointer(): ptr TWidget {.importc ... .}
# Wrapper:
proc getWidget*(): Widget = get_widget_pointer()
The purpose of this is so you can avoid wrap(get_widget_pointer()), and just write let widget = getWidget().
You can guess from the naming of the types what I'm doing this for... eventually, I want to make a more idiomatic wrapper for GTK (Type safe, no ptr, and I'm playing with a couple of crazy features, the most interesting is a type safe connect).
There is one drawback, this adds one level of indirection. Originally, I wanted to place the smart pointer object on the stack, and have it increase/decrease refcount when it is copied or goes out of scope, but I couldn't get it to work with destroy and deepCopy (coming from C++ I expected the latter to work like a copy constructor but I couldn't get it to work). But I think if you use this mainly in GUI code, the overhead is more than compensated by the safety and convenience it gives.
Here is a link to a full, small example:
https://gist.github.com/jdmansour/4fec4b229a4c1da30356
What do you think?
Looks interesting I'll take a look when I have some more time; I've been working on something similar.
https://github.com/onionhammer/onion-nimrod/blob/master/tests/memory.nim
Look at the "stack" macro, I'm not sure what to name it yet, but it essentially makes a non-gc'd pointer to an object on the heap and then uses the destroy() to deallocate it.