Why GTK does not use G_DECLARE_DERIVABLE_TYPE?

Hello,

in the glib/GObject model, when a class is defines with G_DECLARE_DERIVABLE_TYPE(), the macros expand to several other macros, so at the end less code needs to be written. Also struct …ZZZ {ParentName parent_instarce; } is defined and it does not include private data.

The file gtk/a11y/gtkarrowaccessible.h contains:

#define GTK_ARROW_ACCESSIBLE(obj)                      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_ARROW_ACCESSIBLE, GtkArrowAccessible))
#define GTK_ARROW_ACCESSIBLE_CLASS(klass)              (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_ARROW_ACCESSIBLE, GtkArrowAccessibleClass))
#define GTK_IS_ARROW_ACCESSIBLE(obj)                   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_ARROW_ACCESSIBLE))
#define GTK_IS_ARROW_ACCESSIBLE_CLASS(klass)           (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_ARROW_ACCESSIBLE))
#define GTK_ARROW_ACCESSIBLE_GET_CLASS(obj)            (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_ARROW_ACCESSIBLE, GtkArrowAccessibleClass))

typedef struct _GtkArrowAccessible        GtkArrowAccessible;
typedef struct _GtkArrowAccessibleClass   GtkArrowAccessibleClass;
typedef struct _GtkArrowAccessiblePrivate GtkArrowAccessiblePrivate;

struct _GtkArrowAccessible
{
  GtkWidgetAccessible parent;

  GtkArrowAccessiblePrivate *priv;
};

struct _GtkArrowAccessibleClass
{
  GtkWidgetAccessibleClass parent_class;
};

GDK_AVAILABLE_IN_ALL
GType gtk_arrow_accessible_get_type (void);

Providing that g_autoptr works with GtkArrow, this can be rewritten as:

G_DECLARE_DERIVABLE_TYPE(GtkArrowAccessible, gtk_arrow_accessible, GTK, ARROW_ACCESSIBLE, GtkWidget)
typedef struct _GtkArrowAccessiblePrivate GtkArrowAccessiblePrivate;
struct _GtkArrowAccessibleClass
{
  GtkWidgetAccessibleClass parent_class;
};

and _GtkArrowAccessible will not have member priv. To my understanding in this case, all accesses to
GtkArrowAccessibe *arrow=…;
arrow->priv, shall be replaced with
GtkArrowAccessiblePrivate priv = gtk_arrow_accessible_get_instance_private(arrow);

Gtk uses G_DECLARE_DERIVABLE_TYPE only for GtkNativeDialog and G_DECLARE_FINAL_TYPE.

Is there any particular reason why G_DECLARE_DERIVABLE_TYPE and G_DECLARE_FINAL_TYPE are not used more extensively within the gtk codebase, in order to get the code smaller, other the lack of time to rewrite the code?

The G_DECLARE_* macros are a later additions to GObject, and not everything has been ported to use them. Most of GTK predates the macros, and it’s kind of pointless to just go around and change things to get the exact same result.

Additionally, for GTK 3 we cannot change the instance structures without breaking ABI, so we cannot use the G_DECLARE_* macros on existing classes. For GTK 4 we started using G_DECLARE_* in newly added classes, as we don’t have ABI concerns.

Hello,

for G_DECLARE_DERIVABLE_TYPE() and G_DECLARE_FINAL_TYPE() the documentation says “You can only use this function if your parent type also supports g_autoptr().”

What is the rationale to require g_autoptr() support for G_DECLARE_…_TYPE()?

To implement g_autoprt() support, one needs G_DEFINE_AUTOPTR_CLEANUP_FUNC() and the documentation for it says “This macro should be used unconditionally; it is a no-op on compilers where cleanup is not supported.”.

g_autoptr() is more precise, it states “This feature is only supported on GCC and clang.”

Looking at the code, it relies on attribute((cleanup(func))) . This attribute was added to gcc in 2003, so is likely released with GCC 3.4 in 2004.

Looking at http://gcc.gnu.org/c99status.html, the only C99 features added to GCC after 3.4 are extended identifiers, integer promotion rules, inline functions, GLib uses inline functions anyway.

If G_DECLARE_DERIVABLE_TYPE() and G_DECLARE_FINAL_TYPE() are going to be used, why aren’t the compiler requirement for GTK restricted to gcc, clang and C99?

Regards
Дилян

The G_DECLARE_* macros define cleanup functions automatically but those definitions are guarded by compiler checks, so it’s not mandatory to use GCC or Clang; we build GTK and GLib (as well as various projects using them) with MSVC, for instance, with no issue whatsoever.

The documentation states that the parent type must also define cleanup functions for itself—either implicitly, by using G_DECLARE_* macros, or explicitly by using G_DEFINE_AUTOPTR_CLEANUP_FUNC(), as it’s the case for code written before G_DECLARE_* macros were added to GLib— because the implementation of the cleanup attributes for GObject-based types needs to chain up to the parent implementation; this is required because the cleanup function for a GObject is g_object_unref(), and every type inheriting from GObject calls g_object_unref(), not a type_name_unref() function.

Finally: the toolchain requirements for GLib and GTK do include C99 features.

Hello Emmanuelle,

my reading of https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#G-DECLARE-FINAL-TYPE:CAPS

  • g_autoptr() support being added for your type, based on the type of your parent class

You can only use this function if your parent type also supports g_autoptr() .”

is that the the function DECLARE-FINAL-TYPE can only be used, if the parent type also supports g_autoptr. Strictly speaking DECLARE-FINAL-TYPE looks like a macro, as it is in capitals, and g_autoptr looks like a function, as it is in small letters (but is in fact macro and is documented as such). My perception after reading the text is that, DECLARE-FINAL-TYPE can only be used if the parent support g_autoptr, hence the compiler understands attribute(cleanup).

If the text means, that after DECLARE-FINAL-TYPE, g_autoptr on the new type can be used (automatic destruction after leaving the scope), depending on the super type and compiler, but irrespective of this DECLARE-FINAL-TYPE can be used for the other declarations, consider rewording the above citation, e.g. to “

  • g_autoptr() support being added for your type, if the complier is clang or gcc, and if the parent type also supports g_autoptr()”.

Regards
Дилян

Correct. As I said in my reply earlier:

In other words: if you want to use G_DECLARE_FINAL_TYPE or G_DECLARE_DERIVABLE_TYPE to declare a GObject type in your header you must ensure that the parent type of the new type you’re declaring either:

  • uses G_DECLARE_DERIVABLE_TYPE or
  • uses G_DEFINE_AUTOPTR_CLEANUP_FUNC

to declare a clean up function for the g_autoptr() macro.

The compiler support is completely immaterial. g_autoptr() can be extended at any later date if some compiler decides to add support for something similar to GCC’s __attribute__((cleanup)). For instance, if tomorrow Microsoft decided to port the C++ destructors to MSVC and have a (theoretical) __declspec(destruct) attribute, we’d just add support to the G_DEFINE_AUTOPTR_CLEANUP_FUNC() macro transparently.

I tend to agree.

For the documentation of G_DECLARE_FINAL_TYPE, G_DECLARE_INTERFACE, and G_DECLARE_DERIVABLE_TYPE I recommend replacing “You can only use this function if your parent type also supports g_autoptr() .“ with “You can only use this macro if your parent type also supports g_autoptr() .” because G_…_TYPE are macros. This does not help much, as g_autoptr is also a macro and it is not clear to which of both macros “this” refers.

Anyway, considering that support for g_autoptr means utilizing G_DEFINE_AUTOPTR_CLEANUP_FUNC, which is sometimes NO-OP, it is strange that the documentation requires using something that can be NO-OP.

I do understand, that on systems with attribute(cleanup) support, the new type will implicitly get g_autoptr support, however writing portable software means that this support cannot be used.

How about this wording “

  • g_autoptr() support being added for your type, if the parent type also supports g_autoptr()”

without “You can only use this function if your parent type also supports g_autoptr() .”?

This means:

  • If the compiler is not Clang or GCC, and the parent type does not utilize G_DEFINE_AUTOPTR_CLEANUP_FUNC there is no support for g_autoptr for the new type
  • If the compiler is not Clang or GCC, and the parent type does utilize G_DEFINE_AUTOPTR_CLEANUP_FUNC there is no support for g_autoptr for the new type
  • If the compiler is Clang or GCC, and the parent type does not utilize G_DEFINE_AUTOPTR_CLEANUP_FUNC there is no support for g_autoptr for the new type
  • If the compiler is Clang or GCC, and the parent type does utilize G_DEFINE_AUTOPTR_CLEANUP_FUNC, then there is support for g_autoptr for the new type

In all cases G_DECLARE_…_TYPE can be used.

The current documentation prohibits the use of G_DECLARE_…TYPE in the first and third bullet, but these are in no significant way different than the second bullet, where G_DECLARE… is allowed.

Any idea why I received no email for the last post, despite receiving emails for the other replies and not changing my settings in between?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.