Re: Floating references



On Tue, 2017-06-06 at 21:28 +0100, Chris Vine wrote:
On Tue, 6 Jun 2017 22:10:39 +0200 (CEST)
Rafal Luzynski <digitalfreak lingonborough com> wrote:

6.06.2017 21:41 Chris Vine <vine35792468 gmail com> wrote:

[...]
No one is suggesting reworking. This is no more than intellectual
interest in the original design choice.  

I wasn't around when this design choice was made so I can only
guess. I can only repeat what Tristan has already said:
this is a feature of GInitiallyUnowned and its descendants
rather than all GObject instances. At least that was originally,
maybe it was changed later but remained to avoid breaking the
backward compatibility.

GObjects not derived from GInitiallyUnowned are indeed weird, as I think
you are suggesting.  They start with a reference count of 1 but without
an owner.

Ok wait a second... this conversation started out with "why is the
initial ref count not 0 instead of 1 for initially unowned objects".

For the weird case of initially unowned objects, the initial ref count
being 0 or 1 is immaterial, initially unowned objects are already a
"hack", in _any_ case some state must exist on the object to denote
that it is floating, regardless of whether initial count is 0 or 1.

The normal case of an object is initial ref count of 1.

The weird case is initially unowned objects.

Initially unowned is a hack to allow programmers (_exclusively_ C
programmers) to avoid writing out g_object_unref() many times when
constructing a hierarchy of objects, manually in code.


I can see that this discussion is happening from the point of view of
programmers who use GObject directly in C code, and normally use
GObject with GTK widgets, please try to think more generally and beyond
this; the GType system in the abstract is a type system written in C,
here we have to do manually many things which OOP languages do
automatically (when using GObject directly in C).

In a code block in C, you write out:

  {
     /* You now ask for some resource, you own it */
     void *ptr = malloc(...);

     /* Use pointer */

     /* Done with pointer, you can free it */
     free(ptr);
  }

This is the same for a GObject, if you do not free the pointer, then it
is a memory leak.

Calling g_object_new() means that you absolutely *must* own the return
value, initially unowned objects are *weird* because they are a data
type which says:

   "Once I exist, I am not really owned, until something owns me"

This is already error prone because at least in C, if the pointer which
refers to an unowned object leaves scope, that unowned object is
*anyway* going to be leaked; so the caller of g_object_new() on an
initially unowned type *still* has some implied responsibility of
giving it away.

This is different when using GObject from languages which do have OOP
features directly in the language. Language bindings can do garbage
collection on your allocated resources when variables (which normally
consume/release an object reference under the hood) go out of scope, so
there is never any need to call g_object_unref() on an allocated
GObject from Vala or Python.

Today there would mostly be no need for any initially unowned objects,
then come from a time when we used to do:

  /* Creating the UI tirelessly in C code */
  label = gtk_label_new("foo");
  entry = gtk_entry_new();
  box = gtk_box_new(...);

  gtk_box_pack_start(GTK_BOX(box), label, ...);
  gtk_box_pack_start(GTK_BOX(box), entry, ...);

  /* Lets write out 1000 more lines like this because we have
   * not yet discovered GtkBuilder or UI templates...
   */

This kind of stuff was painful to write, painful to maintain, and
painful to see.

Adding an extra explicit g_object_unref() call (which would be
unnecessary in Vala or Python anyway) after each line of
gtk_container_add() or gtk_box_pack_start(), turns your already messy
1000 lines of UI construction code into 1200 lines.

That's why we have the really weird thing that is GInitiallyUnowned,
the regular case of a GObject is ref count of 1 at creation time, and
last reference release causes the dispose() cycles to occur and then
finalize().

Today we have GtkBuilder and UI templates compressed and encoded into
GResources, so there is really no need to invent GInitiallyUnowned
anymore, but it's there because of historical reasons.

Sorry for the long winded reply, as you can see, I really wish we never
had initially unowned objects in GObject :)

Autorelease pools on the other hand make more sense, because it does
not matter whether an object is initially unowned or not, you can
always push one onto an autorelease pool and express the semantic of:

   "I'm giving you this object temporarily, it's up to you to take a
    reference if you want one, otherwise it will be garbage collected
    later, automatically"

Cheers,
    -Tristan



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