Currently not. But you can use ptr and cast to get unsafe weak references and add a finalizer on top of that to get an automatic invalidation. Beware, I didn't test this:
import intsets
type
TMyObject = object
id: int
StrongObject = ref TMyObject
WeakObject = object
id: int
data: ptr TMyObj
var
gid: int # for id generation
valid = initIntSet()
proc finalizer(x: StrongObject) =
valid.excl(x.id)
proc create: StrongObject =
new(result, finalizer)
result.id = gid
valid.incl(gid)
inc gid
proc register(s: StrongObject): WeakObject =
result.data = cast[ptr TMyObj](s)
result.id = s.id
proc access(w: WeakObject): StrongObject =
## returns nil if the object doesn't exist anymore
if valid.contains(w.id):
result = cast[StrongObject](w.data)
Does the following line:
result = cast[StrongObject](w.data)
retain the returned object for the lifetime of the parent accessing the weak reference or does the parent need to GC_ref and GC_unref the casted ref (hopefully wrapped in a template)? What I mean is if code like this would be correct or not:
var p = access(weakObject)
...here the gc runs and collects remaining references...
p.whatever() # <-- valid, or invalid because has been freed?
p.whatever() # <-- valid, or invalid because has been freed?
In general invalid. But the current implementation scans the stack conservatively and so the local 'p' can keep 'weakObject' alive.
So, a question - Are weak references a planned (future) feature, to be directly supported by the language, or will they instead be implemented as code similar to the above?
There is no need to directly support them by the language.
There are two types of weak references, short lived, and long lived. With the previous code short lived ones are possible. How would one implement a long lived weak reference?
Long lived weak references are used in caching, they are memory which can be reclaimed by the GC, but preferably won't unless the system is out of memory. In java terminology this seems to be called weak and soft references. The purpose is mainly to implement caching classes, which can be useful for example in a image gallery software, where the uncompressed image is put into a long lived weak reference, so if the user comes back quickly in the slideshow IO and decompression can be avoided, but the cached memory won't prevent new images from loading as it will be released if needed.
How would one implement a long lived weak reference?
GC_ref it, check from time to time how much memory the process uses and then GC_unref these if memory consumption is over a certain threshold. It's not the most elegant way to implement it, but waiting for "out of memory" on a machine with virtual memory support is not a good idea either. Also I don't want my browser to use up all my memory for caching ...
With these two procs your suggested algorithm can be implemented in a cross platform way: the user registers a hook for a limit, when that limit is reached the proc tries to free the caches, then calls GC_fullCollect and maybe GC_allocated_memory later to check the memory was freed. The proc can also decide to free all or just part of its caches and use whatever algorithm is best for the program.
Since these are just soft constraints there should be no problem of reentrancy: the GC can set a boolean before calling the user's threshold hook and avoid repeated calls until the first call returns. This should avoid exceptional cases where the user's proc frees some memory, then allocates enough to trigger again the hook inside the cleaning callback.
set this variable to provide a procedure that should be called in case of an out of memory event.[...] If the handler does not raise an exception, ordinary control flow continues and the program is terminated
I would expect the handler to attempt to free caches so the failed memory operation could be retried, but if the handler has to raise an exception in any case, what is the use?