[gtk/docs-gtk-org] glib: Add a section on floating references for GObject



commit 433f760146e485305994cd99b05a8047d0eae05e
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Wed Oct 27 10:42:05 2021 +0100

    glib: Add a section on floating references for GObject
    
    The floating refs blurb is attached to the GObject section in gtk-doc,
    but it should live in its own document.

 glib/gobject/floating-refs.md | 128 ++++++++++++++++++++++++++++++++++++++++++
 glib/gobject/gobject.toml.in  |   1 +
 2 files changed, 129 insertions(+)
---
diff --git a/glib/gobject/floating-refs.md b/glib/gobject/floating-refs.md
new file mode 100644
index 0000000000..e9a3d8e8ef
--- /dev/null
+++ b/glib/gobject/floating-refs.md
@@ -0,0 +1,128 @@
+Title: Floating references
+
+# Floating references
+
+**Note**: Floating references are a C convenience API and should not be used
+in modern GObject code. Language bindings in particular find the concept
+highly problematic, as floating references are not identifiable through
+annotations, and neither are deviations from the floating reference
+behavior, like types that inherit from [class@GObject.InitiallyUnowned] and
+still return a full reference from [`id@g_object_new`].
+
+[class@GObject.InitiallyUnowned] is derived from [class@GObject.Object]. The
+only difference between the two is that the initial reference of a
+`GInitiallyUnowned` is flagged as a "floating" reference. This means that it
+is not specifically claimed to be "owned" by any code portion. The main
+motivation for providing floating references is C convenience. In
+particular, it allows code to be written as:
+
+```c
+container = create_container ();
+container_add_child (container, create_child());
+```
+
+If `container_add_child()` calls [`method@GObject.Object.ref_sink`] on the
+passed-in child, no reference of the newly created child is leaked. Without
+floating references, `container_add_child()` can only acquire a reference
+the new child, so to implement this code without reference leaks, it would
+have to be written as:
+
+```c
+Child *child;
+container = create_container ();
+child = create_child ();
+container_add_child (container, child);
+g_object_unref (child);
+```
+
+The floating reference can be converted into an ordinary reference by
+calling `g_object_ref_sink()`. For already sunken objects (objects that
+don't have a floating reference anymore), `g_object_ref_sink()` is
+equivalent to [`method GObject Object ref`] and returns a new reference.
+
+Since floating references are useful almost exclusively for C convenience,
+language bindings that provide automated reference and memory ownership
+maintenance (such as smart pointers or garbage collection) should not expose
+floating references in their API. The best practice for handling types that
+have initially floating references is to immediately sink those references
+after `g_object_new()` returns, by checking if the `GType` inherits from
+`GInitiallyUnowned`. For instance:
+
+```c
+GObject *res = g_object_new_with_properties (gtype,
+                                             n_props,
+                                             prop_names,
+                                             prop_values);
+
+// or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED))
+if (G_IS_INITIALLY_UNOWNED (res))
+  g_object_ref_sink (res);
+
+return res;
+```
+
+Some object implementations may need to save an object's floating state
+across certain code portions (an example is `GtkMenu` in GTK3), to achieve
+this, the following sequence can be used:
+
+```c
+// save floating state
+gboolean was_floating = g_object_is_floating (object);
+g_object_ref_sink (object);
+// protected code portion
+
+...
+
+// restore floating state
+if (was_floating)
+  g_object_force_floating (object);
+else
+  g_object_unref (object); // release previously acquired reference
+```
+
+## Replacing floating references with annotations
+
+You should avoid basing your object hierarchy on floating references, as
+they are hard to understand even in C, and introduce additional limitations
+when consuming a GObject-based API in other languages.
+
+One way to express the ownership transfer between "container" and "child"
+instances is to use ownership transfer annotations in your documentation and
+introspection data. For instance, you can implement this pattern:
+
+```c
+container_add_child (container, create_child ());
+```
+
+without leaking by having `container_add_child()` defined as:
+
+```c
+/**
+ * container_add_child:
+ * @self: a container
+ * @child: (transfer full): the child to add to the container
+ *
+ * ...
+ */
+void
+container_add_child (Container *container,
+                     Child *child)
+{
+  container->children = g_list_append (container->children, child);
+}
+```
+
+The container does not explicitly acquire a reference on the child; instead,
+the ownership of the child is transferred to the container. The transfer
+annotation will be used by language bindings to ensure that there are no
+leaks; and documentation tools will explicitly note that the callee now owns
+the value passed by the caller.
+
+## Replacing floating references with weak references
+
+Another option for replacing floating references is to use weak references
+in place of strong ones. A "container" can acquire a weak reference on the
+"child" instance by using [`method@GObject.Object.weak_ref`]; once the
+child instance loses its last strong reference, the container holding a
+weak reference is notified, and it can either remove the child from its
+internal list, or turn a weak reference into a strong one.
diff --git a/glib/gobject/gobject.toml.in b/glib/gobject/gobject.toml.in
index cd1288405d..c3459fd7e5 100644
--- a/glib/gobject/gobject.toml.in
+++ b/glib/gobject/gobject.toml.in
@@ -37,6 +37,7 @@ urlmap_file = "urlmap.js"
 content_files = [
   "concepts.md",
   "tutorial.md",
+  "floating-refs.md",
 ]
 content_images = [
   "images/glue.png",


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