On Wed, Sep 25, 2002 at 06:01:42AM +0900, William Djaja Tjokroaminata wrote:
> Hi Paul,
> 
> I think this is really a fundamental/philosophical question.  When we
> create a Ruby object in C, should we create the C data from inner to
> outer, or from outer to inner?  In standard C, it does not matter.

I beg to differ.

In C++, objects are ALWAYS allocated outer to inner and initialized
inner to outer, because once an object is constructed, it should be a
valid object.  If an inner object has not yet been constructed, then the
outer object is not a valid object.  This becomes important when
destroying an object that has been halfway constructed (as a result of
an exceptional condition that prohibits completing the object's
construction, for example).

> In Ruby, because of the presence of garbage collector, however, it can
> make a difference between a code which crashes and which does not.

In your case, the problem is not order of construction; it is order of
registration with the garbage collector.

You have the following requirements:
  1. I needs to be constructed and registered with the GC.
  2. O needs to be constructed and registered with the GC.
  3. O cannot be fully constructed until I has been registered with the
     GC.
  4. I must not be freed by the GC until after O has been registered
     with the GC.
  5. You want all this to be as fast as possible.
  6. You will have many I's (inner objects), and don't want to eat too
     much memory on the stack with them.

I hadn't considered requirement#4 before, and it throws me for a loop.
There are a number of possible solutions, but it with mixing
requirements 5 and 6 seems tricky.

> If it is inner to outer, we need to use the stack.  If it is outer to
> inner, we need to do two-step initialization.  Which is the better or even
> probably the right way?  I am surprised that not many people have answers
> or even opinions on this.  (Are we the C-writing Rubyist really a
> minority?)

I suspect that most C extensions are not "stress tested" like your
extensions are; there could easily be bugs lurking in the corners.

I also suspect that most C extensions wrap existing C structures, and do
not have objects that hold references to other Ruby objects.  These
extensions won't run into the problems you describe.

Extensions that do hold references to other Ruby objects often do so
through instance variables; these extensions also avoid the problems you
are having.

> I don't think a "it does not matter" answer will be good, as this should
> be one the disciplines in writing Ruby in C.  Without this discipline, the
> resulting bug may be very hard to trace.
> 
> Regards,
> 
> Bill
> =========================================================================
> Paul Brannan <pbrannan / atdesk.com> wrote:
> > In that case, if you really have a single outer object holding thousands
> > of inner objects, then a two-step initialization might be best.  This is
> > how an Array works; you first create the Array, and after it is created,
> > you put objects into the Array.
> 
> > Paul