Re: Sinkability considered harmful



  Completely agree.  Interesting read too.   I'd just like to add one
more thing.

  g_object_new *should* always return a new reference, to be owned by
the caller.  It usually does, except for g_object_new(GTK_TYPE_WINDOW,
NULL), in which case the caller does not own the object ref.  I don't
quite understand how this happened.  It should not be due to backward
compatibility because this is a new API (in glib 2.0).  So I would add
"g_object_new returning borrowed references considered harmful", to
avoid more problems like this in the future.

  Cheers.

On Tue, 2006-01-03 at 17:07 -0600, Federico Mena Quintero wrote:
> Sinkability considered harmful
> ------------------------------
> 
> Why do we have sinkable objects, i.e. gtk_object_sink()?
> 
> It is a historical artifact.  Early versions of GTK+ did not have a
> consistent or even correct policy for memory management.  
> 
> In 1997, Marius Vollmer (a Guile hacker with experience in garbage
> collection and automatic memory management) revised most of the code
> in GTK+ to use reference counting consistently:
> 
> 	http://mail.gnome.org/archives/gtk-list/1997-November/msg00229.html
> 
> Owen merged some of these changes (gtk+/ChangeLog.pre-1.0):
> 
> Wed Dec 17 21:09:12 1997  Owen Taylor  <owt1 cornell edu>
>   1997-10-13  Marius Vollmer  <mvo zagadka ping de>
> 
>     [...]
> 
>     Revamped reference counting, see the file REFCOUNTING.
> 
> Early in 1998, Tim Janik merged most of the changes into GTK+
> (gtk+/ChangeLog.pre-1.0):
> 
> Fri Jan 30 23:55:03 1998  Tim Janik  <timj gimp org>
> 
> 	* Incorporation of Marius Vollmer's reference counting revolution,
> 	  plus various fixups and additions from myself.
> 
> 	[...]
> 
> 	* gtk/gtkobject.c: new functions gtk_object_finalize,
>  	  gtk_object_notify_weaks, gtk_object_debug, gtk_object_sink,
>  	  gtk_object_weakref, gtk_object_weakunref. implementation of the new
> 	  reference counting scheme for gtkobjects (consult gtk+/REFCOUNTING).
> 
> See the last part of this mail: 
> 	http://mail.gnome.org/archives/gtk-list/1997-November/msg00245.html
> 
> Quote:
> 
> 	The complicated rules about GtkWidgets and their `floating'
> 	flag are there to avoid breaking *all* existing code.
> 
> So, what happened?
> 
> We started using reference counting in a consistent fashion.  Even if
> not all structures and objects derived from GtkObject, they provided
> their own foo_ref() and foo_unref() functions.
> 
> Client code seldom used "internal" objects like GdkFont, so it didn't
> need to ref/unref those objects.  For example, in an expose handler
> you could simply access widget->style->font, as you would not be
> storing that font for usage elsewhere.
> 
> 
> Widgets are special
> -------------------
> 
> GTK+ always had this usage convention for widgets:
> 
>   GtkWidget *the_widget;
> 
>   the_widget = gtk_some_widget_new ();
>   gtk_container_add (some_container, the_widget);
>   /* I no longer own the_widget; some_container owns the base reference */
> 
> The convention is that once you insert a widget in a container, you
> no longer own a reference to the widget.
> 
> Contrast this with a "normal" reference-counted API, where you do this:
> 
> 	Obj *obj;
> 
> 	obj = some_object_new ();
> 	/* reference count of obj is now 1 */
> 
> 	container_add (container, obj);
> 	/* reference count of obj is now 2 or more */
> 
> 	some_object_unref (obj);
> 	/* This code no longer owns a reference to obj, but the
> 	 * container does.
> 	 */
> 
> ... but old code that used GTK+ did *NOT* require you to unref() the
> object after adding it to a container, and we did not want to break
> that code.  WE HAVE LIVED WITH THAT CONVENTION EVER SINCE.
> 
> The "floating" flag was introduced in GtkObject to:
> 
> 	1. keep this convention
> 
> 	2. make things easier for language bindings.
> 
> So, to summarize: the floating flag was added to avoid changing GTK+
> client code, and to make things friendly to language bindings which
> perform their own memory management.  You do *not* need a floating
> flag in a normal reference-counted API.
> 
> All GtkObjects start with the floating flag turned on.  Inside the
> code for containers, you can see this:
> 
> 	gtk_some_container_add (GtkSomeContainer *container, GtkWidget *child)
> 	{
> 		gtk_object_ref (child);
> 		gtk_object_sink (child);
> 		add_child (container->children, child);
> 	}
> 
> With this scheme:
> 
> 1. Right after creation, the initial reference of an object is said to
>    be floating.
> 
> 2. When you put the object in a container, the container first refs
>    the object, then sinks it.
> 
> 	void
> 	gtk_object_sink (GtkObject *object)
> 	{
> 	  if (GTK_OBJECT_FLOATING (object))
> 	    {
> 	      GTK_OBJECT_UNSET_FLAGS (object, GTK_FLOATING);
> 	      gtk_object_unref (object);
> 	    }
> 	}
> 
>    From the viewpoint of the container, this means:  if no one had
>    claimed ownership to the initial reference of the object, I'll
>    claim it myself.  Otherwise, I'll simply acquire a new reference to
>    the object.
> 
> 3. The calling code no longer owns the initial reference.
> 
> 
> Widgets are inconsistent
> ------------------------
> 
> If you had an API where everything was "purely" reference-counted, you
> would always acquire a reference when you needed one, and release it
> when you no longer need it.  This makes using the API reasonably
> easy.  You have to type a bit more to make the call to unref(), but at
> least your code is consistent.
> 
> When certain objects have a floating flag and a sink() method, you as
> a programmer need to keep in mind a special case.  Users of GTK+ have
> kept this in mind for GtkWidget and its descendants since 1998.
> 
> Many APIs have abused float/sink "to make things easier for the
> programmer", so that he doesn't have to unref() an object after
> passing it to a container-like object which acquires a reference.
> Recent culprits include gtk_file_filter_new() and
> gtk_file_chooser_add_filter(), even though filters are not widgets!
> 
> 
> Good practices for new APIs
> ---------------------------
> 
> Just make them purely reference-counted as derived from GObject.  If
> your API has container-like objects which hold other objects, you'll
> need to unref() the children by hand after inserting them in the
> container.
> 
> Using floating references and a sink() method just makes life harder
> for everyone:
> 
> 1. Users have to keep in mind that those objects are special.
> 
> 2. Language bindings have to go through contortions to get the
>    references right.
> 
> 
> Summary
> -------
> 
> Let's not have a floating flag in GObject, as it promotes bad API
> practices.
> 
> Let's keep GtkObject and GtkWidget as they are, as a historical
> artifact, and just let language bindings deal with them as they do
> now.
> 
> APIs which want to reinvent float/sink do so at their own peril.
> 
>   Federico
> 
> 
> _______________________________________________
> gtk-devel-list mailing list
> gtk-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/gtk-devel-list
-- 
Gustavo J. A. M. Carneiro
<gjc inescporto pt> <gustavo users sourceforge net>
The universe is always one step beyond logic

Attachment: signature.asc
Description: This is a digitally signed message part



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