Floating references

classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Floating references

Stefan Salewski-2
Some years ago I read about floating references as described in

https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html

Of course that makes sense.

Newly created objects get ref count 1, but are floating. If they get
put into a container element, floating ref is converted to ordinary
ref, and ref count stays at 1.

But I was wondering, why for newly created objects ref count is not
just zero, so when the element is put into a container it is just
increased to one.

So there must be a reason why it can not work this way. Of course when
ref count drops to zero the element is deleted. But when a newly
created element just has ref count zero, where is the problem?
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Tristan Van Berkom-3
On Tue, 2017-06-06 at 11:50 +0200, Stefan Salewski wrote:
> Some years ago I read about floating references as described in 
>
> https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html
>
> Of course that makes sense.
>
> Newly created objects get ref count 1, but are floating. If they get
> put into a container element, floating ref is converted to ordinary
> ref, and ref count stays at 1.

First, note that this is _only_ for initially unowned objects, which
GtkWidgets and some others happen to be; and this is mostly convenience
to avoid having to type extra g_object_unref() lines in C code.

To be honest I dont feel like this approach really makes sense, I much
prefer the autorelease pool approach taken by NextStep's objective C
implementation, where the semantic of giving away ownership is
expressed by pushing an object onto the nearest autorelease pool on the
call stack; usually as a part of a return statement.

A new object is always on an autorelease pool, and if ownership is not
claimed by the time you exit the nearest autorelease pool stack frame,
it gets cleaned up automatically.

This way you generally communicate through a return statement whether

  A.) You are granting access to an object you retain ownership of

or

  B.) You are giving the object away through your return statement,
      by pushing it onto the nearest autorelease pool on the stack

However, floating refs are what we had with GtkObject and now that
these floating initially unowned things found their way into GObject,
theres not really any way to turn back the clock and change it.


> But I was wondering, why for newly created objects ref count is not
> just zero, so when the element is put into a container it is just
> increased to one.

In a way, it already is.

Whether it is the actual ref_count that is zero, or whether there is
just a separate floating flag I think is quite immaterial; you need to
have some state to mark the floating object after g_object_new()
returns otherwise it is in an invalid state until the first call to
g_object_ref().

The fact that the count itself is 1, is mostly irrelevant.

Cheers,
    -Tristan

_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Rafal Luzynski
In reply to this post by Stefan Salewski-2
6.06.2017 11:50 Stefan Salewski <[hidden email]> wrote:
> [...]
> But I was wondering, why for newly created objects ref count is not
> just zero, so when the element is put into a container it is just
> increased to one.
>
> So there must be a reason why it can not work this way. Of course when
> ref count drops to zero the element is deleted. But when a newly
> created element just has ref count zero, where is the problem?

Let's consider a system where a newly created object has ref count zero.
Assume that you have created an object but changed your mind and
decided you want to delete it. g_object_unref() raises an assert
if ref_count is not > 0. But OK, this assert would have to be removed.
So having ref_count == 0 you can't delete the object because ref_count
is already 0. Or if you allow ref_count to be decremented, as ref_count
is of type guint it would become 0xFFFFFFFF rather than -1.

Then assume that g_object_ref() was called once. The next balanced
g_object_unref() would make the object deallocated. You would have
to call g_object_ref() immediately after creating to make sure the
object exists until you decide to deallocate it.

With floating object you can (you have a choice):

- ref/unref the object any number of times as long as the number
  of unrefs is never greater than the number of refs,
- give an ownership to a container and forget the unref (the container
  will take care of it),
- unref the object to delete it.

It looks like a good design to me. Even if a better system can be
designed I believe it would not be much better and therefore not
worth reworking.

Regards,

Rafal
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Chris Vine-3
In reply to this post by Tristan Van Berkom-3
On Tue, 06 Jun 2017 19:35:40 +0900
Tristan Van Berkom <[hidden email]> wrote:

> On Tue, 2017-06-06 at 11:50 +0200, Stefan Salewski wrote:
> > But I was wondering, why for newly created objects ref count is not
> > just zero, so when the element is put into a container it is just
> > increased to one.  
>
> In a way, it already is.
>
> Whether it is the actual ref_count that is zero, or whether there is
> just a separate floating flag I think is quite immaterial; you need to
> have some state to mark the floating object after g_object_new()
> returns otherwise it is in an invalid state until the first call to
> g_object_ref().
>
> The fact that the count itself is 1, is mostly irrelevant.

I have to say that I have had the same thought as Stefan on this.  All
other intrusive pointer implementations I have seen start at a count
of 0 on creating an object, increment the count to 1 when that object
becomes first owned, and take the change of state from 1 to 0 on the
final unreference as indicating that the object concerned needs to be
freed.

Using a separate flag for the same initial purpose seems pointless: it
is a waste of space.  Possibly the original designer didn't want a count
of 0 to arise in two different circumstances (on creation and on the
final unreference), but that seems a bit weak.  Surely there must have
been some other reason for it?

Chris
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Chris Vine-3
In reply to this post by Rafal Luzynski
On Tue, 6 Jun 2017 21:23:09 +0200 (CEST)
Rafal Luzynski <[hidden email]> wrote:

> 6.06.2017 11:50 Stefan Salewski <[hidden email]> wrote:
> > [...]
> > But I was wondering, why for newly created objects ref count is not
> > just zero, so when the element is put into a container it is just
> > increased to one.
> >
> > So there must be a reason why it can not work this way. Of course
> > when ref count drops to zero the element is deleted. But when a
> > newly created element just has ref count zero, where is the
> > problem?  
>
> Let's consider a system where a newly created object has ref count
> zero. Assume that you have created an object but changed your mind and
> decided you want to delete it.

Then just do what g_object_unref() would do, were the count to be 1:
finalize/free any members requiring it and then free the object itself.

> g_object_unref() raises an assert
> if ref_count is not > 0. But OK, this assert would have to be removed.
> So having ref_count == 0 you can't delete the object because ref_count
> is already 0. Or if you allow ref_count to be decremented, as
> ref_count is of type guint it would become 0xFFFFFFFF rather than -1.
>
> Then assume that g_object_ref() was called once. The next balanced
> g_object_unref() would make the object deallocated. You would have
> to call g_object_ref() immediately after creating to make sure the
> object exists until you decide to deallocate it.
>
> With floating object you can (you have a choice):
>
> - ref/unref the object any number of times as long as the number
>   of unrefs is never greater than the number of refs,
> - give an ownership to a container and forget the unref (the container
>   will take care of it),
> - unref the object to delete it.
>
> It looks like a good design to me. Even if a better system can be
> designed I believe it would not be much better and therefore not
> worth reworking.

In my present state of ignorance, I don't buy it.

No one is suggesting reworking.  This is no more than intellectual
interest in the original design choice.
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Rafal Luzynski
6.06.2017 21:41 Chris Vine <[hidden email]> 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.

Regards,

Rafal
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Chris Vine-3
On Tue, 6 Jun 2017 22:10:39 +0200 (CEST)
Rafal Luzynski <[hidden email]> wrote:

> 6.06.2017 21:41 Chris Vine <[hidden email]> 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.

But on further thought I suspect you are right: the floating reference
was to circumvent this problem.  So I guess the question is why pure
(non-GInitiallyUnowned) GObjects start with a reference count of 1,
instead of a count of 0 as in other similar implementations.  Starting
with a count of 0 would have made floating references unnecessary.

Chris
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Rafal Luzynski
6.06.2017 22:28 Chris Vine <[hidden email]> wrote:
> [...]
> 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.

As far as I understand owned object were supposed to be the widgets
contained inside the containers. Not all widgets are contained (toplevel
windows are not), also not all objects are widgets.

> But on further thought I suspect you are right: the floating reference
> was to circumvent this problem. So I guess the question is why pure
> (non-GInitiallyUnowned) GObjects start with a reference count of 1,
> instead of a count of 0 as in other similar implementations. Starting
> with a count of 0 would have made floating references unnecessary.

I can't tell for sure. Maybe (as I wrote before) the floating reference
feature was not always expected to exist, maybe it simplified some
things, maybe it does not matter that much and the system works the same
no matter if the initial reference count is 0 or 1 or some other number.

Regards,

Rafal
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Greg Ewing
In reply to this post by Chris Vine-3
Chris Vine wrote:
> So I guess the question is why pure
> (non-GInitiallyUnowned) GObjects start with a reference count of 1,
> instead of a count of 0 as in other similar implementations.

CPython starts reference counts at 1, and it works perfectly
well -- the code that allocates the object initially owns a
reference to it, which it is obliged to dispose of in some
way. I can't see why GInitiallyUnowned was thought to be
needed.

--
Greg
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Tristan Van Berkom-3
In reply to this post by Chris Vine-3
On Tue, 2017-06-06 at 21:28 +0100, Chris Vine wrote:

> On Tue, 6 Jun 2017 22:10:39 +0200 (CEST)
> > Rafal Luzynski <[hidden email]> wrote:
> >
> > > > 6.06.2017 21:41 Chris Vine <[hidden email]> 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

_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Tristan Van Berkom-3
In reply to this post by Rafal Luzynski
On Tue, 2017-06-06 at 23:32 +0200, Rafal Luzynski wrote:

> > 6.06.2017 22:28 Chris Vine <[hidden email]> wrote:
> >
> > [...]
> > 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.
>
> As far as I understand owned object were supposed to be the widgets
> contained inside the containers. Not all widgets are contained (toplevel
> windows are not), also not all objects are widgets.

No.

Owned objects are objects which one owns a reference to, the concept of
ownership is a bit hard to explain and follow, because it's hard to
differentiate (there is no real material difference, except in how you
write your code) from other references.

For instance, under the hood, g_signal_emit() will retain a reference
to the emitting object during signal emission, because it requires that
object to stay alive during the course of signal emission, but emitting
a signal can cause callback cycles to occur which result in releasing
the (otherwise) final references to the object.

I would say that g_signal_emit() holds a temporary reference, but there
is *usually* somewhere in a program where ultimately the calling code
expects to be the one who has the final reference to an object, this is
the ownership ref. If the program has no ref count imbalance bugs, then
releasing an ownership reference will *eventually* result in
finalization, once any other temporary references have gone away.

That said, ownership is not always a requisite, but strong references
are; I.e. programs can be constructed where some object is created and
given to a chain/group of objects or code segments, this is not a
regular case for normal OOP patterns.

So yes, container widgets own their children.

Other non-container widgets may also own delegate objects for doing
work, like completions and such.

Non widget / Non UI objects can create and own other delegate objects
for other reasons, completely unrelated to widget hierarchies.

Also, at the most basic level, when you do:

   foo = g_object_new(MY_TYPE_FOO);

You *own* the object, in the sense that ultimately that object is your
responsibility until you either give it away (by passing it as a
parameter and subsequently calling g_object_unref()) or, until you just
decide to dispose of that object by calling g_object_unref() without
ever sharing the object.

Ownership of objects is a requirement for garbage collection in
general, it is not exclusive to the case of GtkWidgets at all.

Cheers,
    -Tristan

_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Floating references

Rafal Luzynski
7.06.2017 09:45 Tristan Van Berkom <[hidden email]> wrote:

>
>
> On Tue, 2017-06-06 at 23:32 +0200, Rafal Luzynski wrote:
> > > 6.06.2017 22:28 Chris Vine <[hidden email]> wrote:
> > >
> > > [...]
> > > 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.
> >
> > As far as I understand owned object were supposed to be the widgets
> > contained inside the containers. Not all widgets are contained (toplevel
> > windows are not), also not all objects are widgets.
>
> No.
>
> Owned objects are objects which one owns a reference to, the concept of
> ownership is a bit hard to explain and follow, because it's hard to
> differentiate (there is no real material difference, except in how you
> write your code) from other references.

Sorry, my typo or too fast thinking. Of course I meant GInitiallyUnowned
object which become owned by the containers. Of course, a reference is the
way that some objects own other objects but g_object_ref_sink() makes
a special kind of ownership, I'll call it an exclusive ownership. It differs
from the regular ownership because it can be called only once, it does not
increase the reference count, and its corresponding g_object_unref()
is supposed to ultimately deallocate the object.

> For instance, under the hood, g_signal_emit() will retain a reference
> to the emitting object during signal emission, because it requires that
> object to stay alive during the course of signal emission, [...]

Yes, this is an example of a regular reference (or a regular
non-exclusive ownership).

> [...]
> So yes, container widgets own their children.
>
> Other non-container widgets may also own delegate objects for doing
> work, like completions and such.
>
> Non widget / Non UI objects can create and own other delegate objects
> for other reasons, completely unrelated to widget hierarchies.
> [...]

That's true, child-container relationship is just an example, the same
concept may be used for other purposes, too.

While at this, I'd like to tell that your another post explains the
problem thoroughly and IMHO completely. Thank you for this.

Regards,

Rafal
_______________________________________________
gtk-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-list
Loading...