GObject Basic Concepts

A brief tutorial on how to write a GObject

Author

NumCosmo developers

Overview

GObject provides object types, inheritance, properties, and virtual methods for C APIs and language bindings. See: GObject Manual, GObject Wikipedia.

Namespaces

The library is divided in two main name-spaces, Ncm (NumCosmoMath) where all generic mathematical and statistical objects and functions are defined, Nc (NumCosmo) where all cosmological related objects and functions are defined. All types must be labeled using the camel-case, and start with the respective name-space. For example, NcmSpline is the type used to store instances of the Spline object which lives in the NumCosmoMath name-space. Similarly, NcHICosmo is the type used for the abstract object defining homogeneous and isotropic models (HICosmo).

Methods, functions and other names

Functions and methods must be lower case and the terms separated by underscores, that is, a method of NcmSpline must be called ncm_spline_method_name. It is acceptable for the method_name to have upper case letters when necessary. For example, nc_hicosmo_Omega_m0 uses the capital Omega to avoid confusion with lowercase omega_m0, which has a different meaning in the cosmological literature.

Macros, enumerator and flags labels should be in uppercase and separated by underscores. See for example NcHICosmoImpl for a flag type. The flag type itself, NcHICosmoImpl, must be in camel-case but its labels are underscore separated uppercase.

A full example of a GObject implementation inside NumCosmo is the NcmModel class description.

Object implementation

An object named NcObjectName implements:

  • nc_object_name_class_init: define methods and properties. Called once per class.

  • nc_object_name_init: initialize each instance, including private members that are not properties. Members of a type such as NcmModelCtrl are initialized here rather than through a property.

  • _nc_object_name_set_property/_get_property: handle property assignment. Every property declared G_PARAM_CONSTRUCT or G_PARAM_CONSTRUCT_ONLY is set during construction, using the value passed to nc_object_name_new or the default if none was passed. Construct-only properties cannot change afterwards. A property that is neither is set only when explicitly passed; its declared default is never applied.

  • _nc_object_name_constructed: perform work that requires constructed property values.

  • _nc_object_name_dispose: release object references with _clear functions. It may run more than once, since GObject calls it repeatedly to break reference cycles, which is why every release here must use _clear. See the GObject memory management documentation.

  • _nc_object_name_finish: release memory not managed by GObject.

Default methods

In NumCosmo we have the following conventions for methods that all objects must implement:

  • nc_object_name_ref: increment ref_count.

  • nc_object_name_clear/_free: decrement ref_count. The _clear variant also accepts NULL and sets the pointer to NULL.

Example

See below a simple example of NumCosmo/GObject implementation.

Header for NcObjectName

#ifndef _NC_OBJECT_NAME_H_
#define _NC_OBJECT_NAME_H_

#include <glib.h>
#include <glib-object.h>

G_BEGIN_DECLS

#define NC_TYPE_OBJECT_NAME (nc_object_name_get_type())

G_DECLARE_FINAL_TYPE(NcObjectName, nc_object_name, NC, OBJECT_NAME, GObject)

/* METHODS */
NcObjectName *nc_object_name_new(gdouble prop1_val);
NcObjectName *nc_object_name_ref(NcObjectName *nc_object_name);
void nc_object_name_free(NcObjectName *nc_object_name);
void nc_object_name_clear(NcObjectName **nc_object_name);

G_END_DECLS

#endif /* _NC_OBJECT_NAME_H_ */

Source for NcObjectName

/**
 * NcObjectName:
 *
 * Object short description
 *
 * Long description
 *
 */

#include "nc_object_name.h"

struct _NcObjectName
{
  /*< private >*/
  GObject parent_instance;
};

typedef struct _NcObjectNamePrivate
{
  gdouble private_double;
} NcObjectNamePrivate;

enum
{
  PROP_0,
  PROP_PROP1,
  PROP_SIZE,
};

/* This object is a child of GObject */
G_DEFINE_TYPE_WITH_PRIVATE (NcObjectName, nc_object_name, G_TYPE_OBJECT);

static void
nc_object_name_init (NcObjectName *obj)
{
  NcObjectNamePrivate * const self = nc_object_name_get_instance_private (obj);

  self->private_double = 0.0;
}

static void
_nc_object_name_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
  NcObjectName *obj                = NC_OBJECT_NAME (object);
  NcObjectNamePrivate * const self = nc_object_name_get_instance_private (obj);

  g_return_if_fail (NC_IS_OBJECT_NAME (object));

  switch (prop_id)
  {
    case PROP_PROP1:
      self->private_double = g_value_get_double (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
_nc_object_name_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
  NcObjectName *obj                = NC_OBJECT_NAME (object);
  NcObjectNamePrivate * const self = nc_object_name_get_instance_private (obj);

  g_return_if_fail (NC_IS_OBJECT_NAME (object));

  switch (prop_id)
  {
    case PROP_PROP1:
      g_value_set_double (value, self->private_double);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
_nc_object_name_dispose (GObject *object)
{
  /* Chain up : end */
  G_OBJECT_CLASS (nc_object_name_parent_class)->dispose (object);
}

static void
_nc_object_name_finalize (GObject *object)
{
  /* Chain up : end */
  G_OBJECT_CLASS (nc_object_name_parent_class)->finalize (object);
}

static void
nc_object_name_class_init (NcObjectNameClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->set_property = &_nc_object_name_set_property;
  object_class->get_property = &_nc_object_name_get_property;
  object_class->dispose      = &_nc_object_name_dispose;
  object_class->finalize     = &_nc_object_name_finalize;

  g_object_class_install_property (object_class,
                                   PROP_PROP1,
                                   g_param_spec_double ("prop1",
                                                        NULL,
                                                        "This is prop is a double between (0.0, 1.0), default 0.5 ",
                                                        0.0, 1.0, 0.5,
                                                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB));
}

/* METHODS */

/**
 * nc_object_name_new:
 * @prop1: a value for prop1
 *
 * A simple constructor.
 *
 * Returns: (transfer full): a newly created #NcObjectName
 */
NcObjectName *
nc_object_name_new (gdouble prop1_val)
{
  NcObjectName *nc_object_name = g_object_new (NC_TYPE_OBJECT_NAME,
                                               "prop1", prop1_val,
                                               NULL);

  return nc_object_name;
}

/**
 * nc_object_name_ref:
 * @nc_object_name: a #NcObjectName
 *
 * Increase reference count by one.
 *
 * Returns: (transfer full): @nc_object_name.
 */
NcObjectName *
nc_object_name_ref (NcObjectName *nc_object_name)
{
  return g_object_ref (nc_object_name);
}

/**
 * nc_object_name_free:
 * @nc_object_name: a #NcObjectName
 *
 * Decrease reference count by one.
 *
 */
void
nc_object_name_free (NcObjectName *nc_object_name)
{
  g_object_unref (nc_object_name);
}

/**
 * nc_object_name_clear:
 * @nc_object_name: a #NcObjectName
 *
 * Decrease reference count by one if *@nc_object_name != NULL
 * and sets @nc_object_name to NULL.
 *
 */
void
nc_object_name_clear (NcObjectName **nc_object_name)
{
  g_clear_object (nc_object_name);
}