GObject in GC implementation Plan

Chris Shoemaker c.shoemaker at cox.net
Thu Mar 22 10:39:21 EDT 2007


On Wed, Mar 21, 2007 at 10:48:12PM -0600, Daniel Espinosa wrote:
> 2007/3/21, Josh Sled <jsled at asynchronous.org>:
> > On Wed, 2007-03-21 at 00:42 -0600, Daniel Espinosa wrote:
> > > Get GObject as the base of GC's objects. With the following advantages:
> > >       - Get ref counting
> > >       - Get signals events
> >
> > Using GObject is a prerequisite of either of the separate "ref counting"
> > and "signals" projects, but aren't advantages that directly follow from
> > using GObject.
> >
> >
> > > ******OPTION 1: PORT QofEntity TO USE GObject AS BASE CLASS
> > > *******OPTION 2: PORT QofInstance TO USE GObject AS BASE CLASS
> > > *******OPTION 3: PORT GC's OBJECT TO USE GObject AS BASE CLASS
> >
> > I read Option1-Step1 and Option2-Step2 as basically the same thing:
> > "everything will just happen".  They're not really "steps"; I don't take
> > away from them a clear plan of action.
> >
> > Option 3 is broken out better, but it doesn't seem as suitable as Option
> > 2.  In particular, I don't see why one would change the type hierarchy
> > twice (in Steps 2 and 5).  As well, it seems pretty agreeable all around
> > to merge QofInstance and QofEntity from the start.  At least for the
> > purposes of discussion, let's call this merged type "GncObject".
> >
> > I'd agree with Chris; Option 2 is probably the better path.  Or maybe a
> > modified version of Option 3, where:
> >
> > - QofInstance and QofEntity are combined
> >
> > - The GnuCash types then subclass GncObject.
> >
> >   - QofInstance fields are just inherited (not included by pointer)
> >
> > - Minimal changes to use G[nc]Object.  I'm thinking, here, for example:
> >
> >     // ..._get_type() { ...g_type_static_register()... }
> >     // ...
> >
> >     Account*
> >     xaccAccountMalloc()
> >     {
> >         Account *a = g_object_new(GNC_ACCOUNT_TYPE, NULL);
> >         // ...existing Account setup...
> >         return a;
> >     }
> >
> >   ...and, well, that's about all.  No signal or property registration,
> >   in particular.
> >
> Any GObject I'll setup will use properties or signal registration,
> unless they *must* need it.

I assume you meant here that you will _not_ use ...

> >
> > [from Option 3...]
> > > Step 4:
> > > Setup QofInstance to be a GObject and be sure to have a correct
> > > construction/destruction process, this will ensure a correct
> > > refcounting.
> >
> > I'd suggest — in any plan — deferring handling "correct"
> > construction/destruction and ref counting to a later phase of work.
> >
> 
> The realy point here is to ensure the construction/destruction of
> QofInstance and its base class GObject, when
> g_object_new/g_object_unref is called, I need to think how to call
> g_object_new and ensure the GObject's mechanisms work fine for the
> GC's and QOF construction/destruction process with out modify a lot of
> code at the same time.
> 
> > In particular, here's what I see happening.  Once you start to modify
> > (say) xaccFreeTransaction() to be "correct", it will want to look like:
> >
> >     xaccFreeTransaction(Transaction *t)
> >     {
> >         g_object_unref(t);
> >     }
> >
> > ...then it only makes sense for its dispose handler to look like...
> >
> >     {
> >         GList *splits = ...;
> >         g_list_foreach(splits, g_object_unref, ...);
> >     }
> >
> > ...which means you have to have "correct" both ref and unref behavior
> > for the Splits, which means, they need a "correct" dispose handler
> > like...
> >
> >     {
> >         g_object_unref(split->account);
> >     }
> >
> > ...which means ... for it to be "correct", everything needs to happen
> > all at once.  It quickly gets to a point where a bunch of changes need
> > to be made to every file at the same time, increasing the chance that
> > the whole set isn't clear or clearly acceptable.
> >
> > I don't think that that necessarily needs to be the case. Better
> > construction/destruction and ref-counting can be phased in.  In
> > particular, I think there are related groups of objects (Maybe {Account,
> > Split, Transaction}.  {GncCommodity, GncPrice, GncNumeric} ... &c.) that
> > could ref-count with each other, probably while intentionally ignoring
> > other groups of objects.  Along the way it wouldn't be fully "correct"
> > nor complete, but it'd be much more tractable.
> >
> 
> I realy want to make as less changes as possible, thats why I'm
> sharing this plan.
> 
> The Option 3 is for get GObject in the early steps and when GncObject
> was finished change (this process is realy easy to do) change the base
> class to GncObject.
> 
> If we gain GC's objects to be GObject some other could use, for
> example, a signal "modified" in a Transaction to create two
> transactions to separate the "sale" and the "tax" of the transaction
> when needed, a feature some one (including me) wants in GC; and get
> advantages even if it doesn't use GncObject as its base class yet.

I'm not exactly sure what you're saying here, but remember that this
plan is about functional intermediate steps - but they're still
intermediate.  We don't intend to _leave_ the conversion half-way
done, even though we do want it to be _working_ when only half-way
done.

> Please reconsider again, and think about the possibilities.
> 
> If Option 2 is taken, take in a count that any GC object that use
> GncObject as its base class *needs* to be setup to be a GObject in
> order to ensure a good work of it, if I could create a GncObject alone
> (using g_object_new (GNC_TYPE_OBJECT, NULL) ) I can take the objects
> by group but the GncObject member *must* be a pointer, if not I need
> to setup all of then at the same time and the modifications will be a
> lot and may be dificult to follow; as Josh Sled said "increasing the
> chance that the whole set isn't clear or clearly acceptable".

I think you may have misunderstood Josh's comments.  He was responding
to your comment about "correct" construction/destruction/ref-counting.
I think his point is that you can convert the engine objects to
GObjects, using the g_object_new() and g_object_unref() in place of
the current allocation/deallocation functions, but without actually
tracking references between objects.

Clearly, this isn't really the best use of GObject.  That's okay -
we'll get there eventually.  For now, the engine objects explicitly
manage the destruction of objects they "own".  This will still work if
the objects are all GObjects.  Conceptually, it's as if the "Engine"
maintains a single reference on all engine objects.  There will only
be the one reference added by the g_object_new(), and then unrefed at
the end of the object's lifetime.  No calls to g_object_ref().

We can do "correct" reference tracking in a later step.  Do you see
how this would work?  

I suggest actually converting one object, like Account to use GObject
and inherit from a GObject-based QofInstance.  And send the diff to
-devel so we can all be on the same page.  This should give an idea of
what is required for all engine objects.

-chris


More information about the gnucash-devel mailing list