Weak references for GObject



Why weak references
===================

One obvious why we need weak references in GObject is that with
reference counting, we can't always keep strong references,
or we'll create cyclic reference counts.

Note that when using language bindings, there is no way of specifying
whether a reference is strong or not, so we typically need to
supplement reference counting with a "break references" operation of
some sort.  (E.g., GtkObject::destroy)

However, there are some other reasons why weak references can be
useful - after all, languages like Java have weak references,
even though they don't use reference counting; in such languages
weak references are used for:

 - Keeping a cache or canonicalized mapping, so that repeated loads of
   a single object always return the same object.

 - Handling cleanup of resources associated with an object in
   a more flexible way than may be provided by finalization.

Issues
======

 - Do we allow "resurrecting" the object from the weak reference?
   That is, when the weak reference is notified, can we increment
   a strong reference count and keep the object from being destroyed?

   This is useful in basically one case - when you want to have
   a cache of the last N most recently freed objects. 

   The objection to allowing resurrection is that it is unnatural
   to almost every form of memory management other than straight-forward
   reference counting, and most other object systems don't allow
   it. If we allow it, then we are allowing people to, perhaps
   unwittingly, tie the structure of their code to a pecularity of
   the way the GObject system works now.

   Doing a N-most-recently-freed object cache in most
   garbage-collected languages is simply impossible -- though
   Java, does allow something a bit like this with soft-references --
   references which are dropped when memory is needed.

 - What is the relationship between the weak references and 
   GtkObject::destroy? In (almost?) every case where we want to 
   keep a weak reference to a GtkObject object, we want to drop the
   reference when gtk_object_destroy() is called.

   There has been some objection that these aren't really the same
   thing. With the idea being, that when you connect to ::destroy,
   you should hold a strong reference, and ::destroy is an optional 
   request to break that reference, that might be ignored.
 
   Since some times you _have_ to hold the strong reference, (for 
   example, when you are programming in Perl/GTK+), clearly true
   weak references can't substitute for ::destroy. However, I can't
   think of any places where you actually want to hold a weak
   reference over ::destroy, so early-notifying weak references
   at destroy time should be fine.

   [ Note that signals are disconnected at ::destroy time, so any
     customization you've done with signals will be removed ]

Current
=======

Currently, the only weak reference facility we have on GObject is
notification on object data destruction.

Object data destruction is done in the virtual method implementation
of GObject::finalize. (Since ::finalize handlers are required to
chain up, there is no difference between doing this here and doing
it after calling finalize().)

At this point we have the properties:

 - The memory for the instance has not yet been freed, so the instance
   pointer uniquely identifies the object.

 - All finalize methods have been called, so no references to the
   instances fields can be made.

 - Resurrection is impossible.

There is no connection between object data and GtkObject::destroy.
Object data isn't removed until finalize time.

Proposal
========

My proposal is very simple. We add:

 typedef void (*GWeakNotify) (GObject *object, gpointer data);

 void g_object_weak_ref   (GObject     *object,
		           GWeakNotify  notify,
			   gpointer	data);
 void g_object_weak_unref (GObject     *object,
	 		   GWeakNotify  notify,
			   gpointer	data);

The only guarantee about when these will be called is that
all weak references will be notified before the object's
finalize virtual method is called. Reincarnantion from
a weak reference notifier is not allowed.

(Notifying before ->finalize() is called, not after, is meant
to be a bit safer against reentrancy problems in finalize methods.)

And:

 void g_object_dispose (GObject *object);

Which notifies all weak references, and removes all signals. (Calls
g_signal_handlers_destroy()). g_object_dispose() will be called
from gtk_object_destroy().

If resurrection for cache purposes is considered necessary (I don't
consider it so), then I'd like to separate it out into a clearly
defined separate facility - something like:

 g_object_add_last_ref_notifier();

That can be emblazoned with all the appropriate warnings.




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]