Object properties and how to traverse quickly to a property

Hi all,

I’m having fun making some objects at home using GObject-2.0. I created a Person object with these private members:

gchar *name;
gint age;
gboolean gender; (simplified, don't judge me)
Person *father;
Person *mother;

Now I have installed all of these as properties and was able to use the set_property and get_property methods to set and get each property as I would like. However, I’m struggling with traversing to the property I want, for example, if I want to get:

PersonA.father.name

I can use

g_object_get_property(G_OBJECT(PersonA), "father", &gval);
father = g_value_get_object(&gval);
g_object_get_property(G_OBJECT(father), "name", &gval2);
name = g_value_dup_string(&gval2);

and so on. Now as you can see, it is quite a hassle if I want to access the name of the person’s great grandfather:

PersonA.father.father.father.name

So the question is, is there a more convenient way to traverse the hierarchy and get to the property I want?

Your help is appreciated. And if I’m doing anything wrong, please don’t hesitate to point it out.

Best regards,
SL

If you had getter and setter functions for those properties, which is usually recommended, it would get a bit easier, as those would provide strongly typed interfaces, so callers would not need to manually deal with GValue.

After implementing those as described in the docs, you would end up with something like:

const YourPerson *father = your_person_get_father (personA);
const YourPerson *grandfather = your_person_get_father (father);
const YourPerson *great_grandfather = your_person_get_father (grandfather);
const char *great_grandfather_name = your_person_get_name (great_grandfather);

You might then think about adding convenience functions to make this easier, e.g.

const char *
get_father_ancestor_name (const YourPerson *person, int generations)
{
  // Here would be type-checks, return_val_if_fail(), etc.

  for (int i = 0; i < generations; ++i)
    {
      person = your_person_get_father (person);
      // Here would be handling for if their father was unknown = NULL
    }

  return your_person_get_name (person);
}

Or you could just nest getter function calls, but as that won’t lead to very readable code, I’ll pass on providing an example. :smiley:

For the syntax you gave:

PersonA.father.name

There is GtkExpression, which mentions a similar syntax, but I’m not familiar with it and so not sure whether it is directly constructible from said syntax or that is only for illustration - nor does it help if you’re using using GObject and not GTK (or GTK < 4).

Thank you dboles,

I think the GtkExpression class is what I’m looking for. It’s still not that convenient, but it will do if I know ahead of time what I’m looking for. It will save me time implementing getters and setters for each property.

    GtkExpression *father = gtk_property_expression_new(PERSON_TYPE, NULL, "father");
    GtkExpression *grandfather = gtk_property_expression_new(PERSON_TYPE, father, "father");
    GtkExpression *greatgrandfather = gtk_property_expression_new(PERSON_TYPE, grandfather, "father");
    GtkExpression *greatgrandfather_name = gtk_property_expression_new(PERSON_TYPE, greatgrandfather, "name");

and then when I want to pull that value for arbitrary person, I can do:

    GValue gval = G_VALUE_INIT;
    gtk_expression_evaluate(greatgrandfather_name, person, &gval);
    const char * name = g_value_get_string(&gval);

Definitely not something that would help while you’re still figuring it out, but it is indeed a quick way to traverse the hierarchy if you know ahead of time where you’re going. I guess if I want even more syntactic sugar I will need to go to a real object-oriented programming language.

Actually, it would be great if we can implement a version of gtk_property_expression_new where we can put multiple levels of expressions at once, like:

GtkExpression *greatgrandfathers_name = 
               gtk_property_expression_chain_new( /* the name is for illustrative purposes only*/
                                                    PERSON_TYPE, "father", 
                                                    PERSON_TYPE, "father",
                                                    PERSON_TYPE, "father",
                                                    PERSON_TYPE, "name",
                                                    NULL /* to signify end of chain */
                                                    );

I don’t know where I can add a suggestion for this, I know I’m not smart enough to code it just think that it is a tad more convenient if we want to chain expressions.

1 Like

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