Object-Oriented struct Model in C

Hi,

In the Ruby-C world, we can make an association between a Ruby class and a
C struct through the use of Data_Wrap_Struct(). But in the Ruby world, a
Ruby class can inherit from a parent, which in turn inherits from its
parent, and so on. Suppose each class in this inheritance chain has
different data in its struct. Is the following a good model for the
corresponding C struct’s?

typedef struct
{
    /* pointer to parent */
    void *parentData;
    void (*parentMarkFunc) (void*);
    void (*parentFreeFunc) (void*);

    /* class-specific data */
    ....
} sClass_Any;

(Is there any reference on how to do object-orientation in C? Well, C++
is excluded for now.)

Regards,

Bill

This will work just fine. There’s a little bit of extra run-time
overhead from the extra pointer dereferencing you will do, and you will
use a small amount of unnecessary memory from storing these pointers.
If you want a bit of extra speed, then you can do the following…

If you only need single inheritance and not multiple inheritance, then
you could write:
typedef struct
{
int x;
int y;
} Base;

typedef struct
{
Base b;
int z;
} Derived;

this would be analgous to:
class Base
attr_accessor :x
attr_accessor :y
end

class Derived < Base
attr_accessor :z
end

given a Derived, you can cast up to a Base without worrying about the
exact structure of your class hierarchy:
Derived *d = malloc(sizeof(Derived));
Base b = (Base)d;

This is exactly how GTK+ does its inheritance (with the aid of some
helper functions that add a little extra type safety).

Also, note that you don’t need a function pointer for the mark and free
functions, unless each instance gets its own mark or free function. The
mark and free functions should be associated with the object’s class,
not the instance of the class. With a good naming system, some macros,
and the ## operator, you can almost hide them completely.

Paul

···

On Tue, Sep 24, 2002 at 10:40:37PM +0900, William Djaja Tjokroaminata wrote:

typedef struct
{
    /* pointer to parent */
    void *parentData;
    void (*parentMarkFunc) (void*);
    void (*parentFreeFunc) (void*);

    /* class-specific data */
    ....
} sClass_Any;

William Djaja Tjokroaminata wrote:

Hi,

In the Ruby-C world, we can make an association between a Ruby class and a
C struct through the use of Data_Wrap_Struct(). But in the Ruby world, a
Ruby class can inherit from a parent, which in turn inherits from its
parent, and so on. Suppose each class in this inheritance chain has
different data in its struct. Is the following a good model for the
corresponding C struct’s?

typedef struct
{
    /* pointer to parent */
    void *parentData;
    void (*parentMarkFunc) (void*);
    void (*parentFreeFunc) (void*);

    /* class-specific data */
    ....
} sClass_Any;

(Is there any reference on how to do object-orientation in C? Well, C++
is excluded for now.)

My turn to sound like a broken record…

The CShadow module (in cgenerator on RAA) gives you this functionality.
It opts for time rather than space efficiency, so there is a lot of code
duplication. However, it is managed for you, so this is only a problem
if you want small executables.

Here’s a simple example with inheritance:

require ‘cgen/cshadow’

class Parent
include CShadow

 shadow_attr_accessor :ruby_str => String
 shadow_attr_accessor :c_int => "int c_int"

end

class Child < Parent
shadow_attr_accessor :obj => Object
end

Parent.commit
# we’re done adding attrs and methods, so make.

x = Child.new
x.ruby_str = “foo”
x.obj = [1,2,3]
x.c_int = 3

The generated code looks, in part, as follows. Note that
CGenerator/CShadow produces quite readable C code; I have snipped but
not changed anything. In the Parent.h header file we have:

typedef struct Parent_Shadow {
VALUE self;
VALUE ruby_str; // String;
int c_int;
} Parent_Shadow;

typedef struct Child_Shadow {

   /* Parent_Shadow members */
   VALUE self;
   VALUE ruby_str; // String;
   int c_int;

   VALUE obj; // Object;

} Child_Shadow;

Again, members are duplicated, which would be awful if you wanted to
manually maintain the code, but who wants to do that :slight_smile:

In the Parent.c file, we have:

void mark_Parent_Shadow(Parent_Shadow *shadow)
{
rb_gc_mark((void *)shadow->self);
rb_gc_mark((void *)shadow->ruby_str);
}

void mark_Child_Shadow(Child_Shadow *shadow)
{
rb_gc_mark((void *)shadow->self);
rb_gc_mark((void *)shadow->ruby_str);
rb_gc_mark((void *)shadow->obj);
}

and similarly for the free functions, persistence functions, etc. The
#new method generated by CShadow is where rb_obj_call_init() gets
called. Note that initialization of shadow attributes is customizable.

VALUE new_module_Child_singleton_method(int argc, VALUE *argv, VALUE
self)
{
VALUE object;
Child_Shadow *shadow;

   object = Data_Make_Struct(self,
              Child_Shadow,
              mark_Child_Shadow,
              free_Child_Shadow,
              shadow);
   shadow->self = object;

   shadow->ruby_str = Qnil;
   shadow->obj = Qnil;

   rb_obj_call_init(object, argc, argv);

   return object;

}

The #ruby_str= method only needs to be defined for Parent, because, of
course, Ruby itself handles inheritance of methods. Note the type
checking, which is done for the ruby_str member but not for the obj member.

VALUE ruby__str_equals_module_Parent_method(int argc, VALUE *argv,
VALUE self)
{
VALUE arg;
Parent_Shadow *shadow;

   rb_scan_args(argc, argv, "1", &arg);

   if (!NIL_P(arg) &&
       rb_obj_is_kind_of(arg, module_String) != Qtrue)
     rb_raise(module_TypeError,
              "argument arg declared String but passed %s.",
              STR2CSTR(rb_funcall(
                rb_funcall(arg, ID_type, 0),
                ID_to__s, 0)));

   Data_Get_Struct(self, Parent_Shadow, shadow);
   shadow->ruby_str = arg;
   return arg;

}

Hi,

given a Derived, you can cast up to a Base without worrying about the
exact structure of your class hierarchy:
Derived *d = malloc(sizeof(Derived));
Base b = (Base)d;

Thanks for giving the excellent idea on doing the object-orientation on
the data part without deferencing. I like it very much. In fact, I just
asked a similar question on comp.lang.c several weeks ago.

Also, note that you don’t need a function pointer for the mark and free
functions, unless each instance gets its own mark or free function. The
mark and free functions should be associated with the object’s class,
not the instance of the class. With a good naming system, some macros,
and the ## operator, you can almost hide them completely.

Regarding this, I am not so sure. Under arbitrarily complex nested struct
with a mix of VALUE’s and ordinary C data, I think it will be a really
hard work for the great-great-great-grandchildren on defining its mark and
free functions for its class. With the method that I proposed initially,
I think an inheritance level can just define

static void mark_me (sMyStruct* s)
{
    /* mark my own VALUE's */
    ....
    /* mark my parent */
    s->parentMarkFunc (s);
}

Especially, when the parent Ruby class is never constructed, i.e, its
Data_Wrap_Struct() is never called, we have to do it this way, don’t we?

(In Ruby, rb_obj_call_init() is propagated through all the parents, but
isn’t that for each class Data_Wrap_Struct() is usually called before
rb_obj_call_init()? In other words, calling rb_obj_call_init() may not
call all the parents’ Data_Wrap_Struct()'s.)

Regards,

Bill

···

Paul Brannan pbrannan@atdesk.com wrote:

Hi Joel,

Thanks for contributing. Actually I just scanned your cgenerator in RAA
last night as I recalled your post on the subject “Ruby
Aesthetics”. However, I got discouraged when I read that the interface is
described in Ruby. I am looking for a more “pure C” description. I
skipped reading your C source code…

Regards,

Bill

···

==========================================================================
Joel VanderWerf vjoel@path.berkeley.edu wrote:

My turn to sound like a broken record…

The CShadow module (in cgenerator on RAA) gives you this functionality.
It opts for time rather than space efficiency, so there is a lot of code
duplication. However, it is managed for you, so this is only a problem
if you want small executables.
(deleted)

What I’m suggesting is something like this:

/* We define a naming convention for a function func in class Klass:

  • Klass_func
  • We also require that a class Klass with base class Base will have a
  • macro:
  • Klass_Base
  • so at compile-time we can know who the base class is.
    */

/* Some macros from the Boost preprocessor library /
/
http://cvs.sf.net/cgi-bin/viewcvs.cgi/boost/boost/boost/preprocessor/cat.hpp */
#define BOOST_PP_CAT(X,Y) BOOST_PP_CAT_DELAY(X,Y)
#define BOOST_PP_CAT_DELAY(X,Y) BOOST_PP_DO_CAT(X,Y)
#define BOOST_PP_DO_CAT(X,Y) X##Y

#define BASE_OF(klass) klass##_Base
#define CALL_BASE(klass, func)
BOOST_PP_CAT(
BOOST_PP_CAT(BASE_OF(klass), _),
func)
#define CAST_TO_BASE(klass, x)
(BASE_OF(klass) *)(x)
#define CALL_BASE_MARK(klass, x)
(CALL_BASE(klass, mark(((BASE_OF(klass) *)x))))

typedef struct
{
/* … */
} Base;

static void Base_mark(Base * b)
{
printf(“Base_mark\n”);
}

typedef struct
{
Base b;
} Derived;
#define Derived_Base Base

static void Derived_mark(Derived * d)
{
printf(“Derived_mark\n”);
CALL_BASE_MARK(Derived, d);
};

The syntax isn’t intuitive, but your mark function is looked up at
compile-time instead of at run-time. If a small loss in maintainability
outweighs the speed gain, then you probably shouldn’t use this trick.

Paul

···

On Wed, Sep 25, 2002 at 01:01:13AM +0900, William Djaja Tjokroaminata wrote:

Regarding this, I am not so sure. Under arbitrarily complex nested struct
with a mix of VALUE’s and ordinary C data, I think it will be a really
hard work for the great-great-great-grandchildren on defining its mark and
free functions for its class. With the method that I proposed initially,
I think an inheritance level can just define

static void mark_me (sMyStruct* s)
{
    /* mark my own VALUE's */
    ....
    /* mark my parent */
    s->parentMarkFunc (s);
}

Hi Paul,

Thanks for the explicit example. I see, so we use some naming convention
and take advantage of the C pre-processor to determine the function at
compile time. It seems that this approach is very maintainable and much
better than keeping the function pointers. (Hey, can I then actually
write object-oriented model using only C from scratch easily? :slight_smile: I don’t
know about objective-C.)

On another slightly different subject, I think last time it was suggested
in C object creation, one approach is to create the inner objects before
the outer objects. However, assuming arbitrarily complex and nested mix
of VALUE’s and C data in the struct’s, I don’t think this approach is
foolproof. The problem is if when creating the inner objects the gc
actually gets invoked, these inner objects are swept away. I don’t know
whether the double initialization technique is really foolproof.

Regards,

Bill

···

==============================================================================
Paul Brannan pbrannan@atdesk.com wrote:

What I’m suggesting is something like this:

/* We define a naming convention for a function func in class Klass:

  • Klass_func
  • We also require that a class Klass with base class Base will have a
  • macro:
  • Klass_Base
  • so at compile-time we can know who the base class is.
    */

#define BASE_OF(klass) klass##_Base
#define CALL_BASE(klass, func)
BOOST_PP_CAT(
BOOST_PP_CAT(BASE_OF(klass), _),
func)
#define CAST_TO_BASE(klass, x)
(BASE_OF(klass) *)(x)
#define CALL_BASE_MARK(klass, x)
(CALL_BASE(klass, mark(((BASE_OF(klass) *)x))))

Thanks for the explicit example. I see, so we use some naming convention
and take advantage of the C pre-processor to determine the function at
compile time. It seems that this approach is very maintainable and much
better than keeping the function pointers. (Hey, can I then actually
write object-oriented model using only C from scratch easily? :slight_smile: I don’t
know about objective-C.)

I wouldn’t exactly call this easy; with the code I’ve written, you still
don’t have type checking or virtual functions or a whole lot of features
you need to write object-oriented code. Take a look at GTK+; they’ve
already done a lot of this work for you.

On another slightly different subject, I think last time it was suggested
in C object creation, one approach is to create the inner objects before
the outer objects. However, assuming arbitrarily complex and nested mix
of VALUE’s and C data in the struct’s, I don’t think this approach is
foolproof. The problem is if when creating the inner objects the gc
actually gets invoked, these inner objects are swept away. I don’t know
whether the double initialization technique is really foolproof.

Put a reference to the inner object on the stack immediately after
calling Data_Wrap_Struct, and the object won’t get collected until the
some time after the stack is unwound.

Paul

···

On Wed, Sep 25, 2002 at 02:21:13AM +0900, William Djaja Tjokroaminata wrote:

Hi,

Well, putting the inner objects on the stack may require a large stack (we
are assuming arbitrarily complex and deeply nested data structure). If we
do the double initialization approach, we first initialize the struct
itself (mostly to zero), and then assign the inner objects directly to the
struct data.

Is this simply a classic time-space trade-off? Maybe not, because we have
to eventually reassign the references from the stack to the struct
data. So, is the double initialization approach actually better?

Regards,

Bill

···

============================================================================
Paul Brannan pbrannan@atdesk.com wrote:

Put a reference to the inner object on the stack immediately after
calling Data_Wrap_Struct, and the object won’t get collected until the
some time after the stack is unwound.

Paul

Don’t put the object itself on the stack, put the VALUE that refers to
it on the stack.

Paul

···

On Wed, Sep 25, 2002 at 03:01:18AM +0900, William Djaja Tjokroaminata wrote:

Hi,

Well, putting the inner objects on the stack may require a large stack (we
are assuming arbitrarily complex and deeply nested data structure). If we
do the double initialization approach, we first initialize the struct
itself (mostly to zero), and then assign the inner objects directly to the
struct data.

Oh, yes, yes, that was exactly what I meant when I reffered to putting the
object/VALUE on the stack. (Beside, what good is to put the actual object

···

on the stack? The gc just scans the stack for VALUE detection.) Bill ========================================================================= Paul Brannan pbrannan@atdesk.com wrote:

Don’t put the object itself on the stack, put the VALUE that refers to
it on the stack.

Paul

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

···

On Wed, Sep 25, 2002 at 05:01:34AM +0900, William Djaja Tjokroaminata wrote:

Oh, yes, yes, that was exactly what I meant when I reffered to putting the
object/VALUE on the stack. (Beside, what good is to put the actual object
on the stack? The gc just scans the stack for VALUE detection.)

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. In
Ruby, because of the presence of garbage collector, however, it can make a
difference between a code which crashes and which does not.

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 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

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.

···

On Wed, Sep 25, 2002 at 06:01:42AM +0900, William Djaja Tjokroaminata wrote:

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

Hi Paul,

Thanks a lot for the comprehensive information. My responses are below.

···

============================================================================
Paul Brannan pbrannan@atdesk.com wrote:

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.


I have thought about this last night. One problem with
“outer-to-inner” is (3), with the result of a lot of “if”'s in the mark
and free functions, which really does not support (5). On the other hand,
using “inner-to-outer”, we need to use stack in regards to (4), but one
problem is (6). Also, suppose the number of VALUE’s is not known at
compile time; putting a dynamic array of VALUE’s in the stack will not
help, will it? (Ruby just detects a VALUE pointer, not an array of
VALUE’s) Does this mean using “inner-to-outer” we have to create at
least a single stack/temporary VALUE variable of type Ruby Array to hold
all those I’s temporarily? (You see how complicated it may become for any
arbitrarily complex and deeply-nested data structure.)


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.


Totally agree. It seems that even a fundamental problem like this is not
a fully-exploited field in Ruby. I am wondering, because “writing C in
the presence of mark-and-sweep gc” looks like a general problem, how do
people outside Ruby do it? (Just like the Gtk library, which shows an
example of object-inheritance format using C struct’s and macros.) I
think this is one more reason to create as much independence as possible
between the C-part and the Ruby-part, i.e., not only for performance, but
also to prevent bugs from happenning.

Regards,

Bill

I have thought about this last night. One problem with
“outer-to-inner” is (3), with the result of a lot of “if”'s in the mark
and free functions, which really does not support (5). On the other hand,
using “inner-to-outer”, we need to use stack in regards to (4), but one

You don’t really need references to all the inner the objects on the
stack; you could have a reference to an object that holds references to
all your inner objects.

problem is (6). Also, suppose the number of VALUE’s is not known at
compile time; putting a dynamic array of VALUE’s in the stack will not
help, will it? (Ruby just detects a VALUE pointer, not an array of
VALUE’s) Does this mean using “inner-to-outer” we have to create at

An array of VALUES allocated with ALLOCA would work, as long as it is
aligned properly on the stack. This uses more stack space than a Ruby
Array, but is cheaper to construct.

least a single stack/temporary VALUE variable of type Ruby Array to hold
all those I’s temporarily? (You see how complicated it may become for any
arbitrarily complex and deeply-nested data structure.)

It doesn’t have to be an Array, though an Array would work.

Also note that if you have a structure like this:

           +-A
      Top--|
           +-B--+-C
                >
                +-D

Then you only need to keep references C and D on the stack while
registering B; you only need to keep references to A and B while
registering Top (since C and D are already referred to by B).

I don’t think, then, that the level of nesting matters (except if you
are worried about running out of stack space); you only need be
concerned about the number of objects at any given level.

Paul

···

On Wed, Sep 25, 2002 at 10:42:53PM +0900, William Djaja Tjokroaminata wrote:

You don’t really need references to all the inner the objects on the
stack; you could have a reference to an object that holds references to
all your inner objects.

But at any level, if that object that holds references to the inner
objects was not created using Data_Wrap_Struct(), there is no way for it
to mark the inner objects, is there?

An array of VALUES allocated with ALLOCA would work, as long as it is
aligned properly on the stack. This uses more stack space than a Ruby
Array, but is cheaper to construct.

Very good point, Paul.

Also note that if you have a structure like this:

           +-A
      Top--|
           +-B--+-C
                >
                +-D

Then you only need to keep references C and D on the stack while
registering B; you only need to keep references to A and B while
registering Top (since C and D are already referred to by B).

Actually, what is the meaning of “registering B”? Is it
rb_gc_register_address()? I am assuming here only the Top object is
created using Data_Wrap_Struct(). (If we use rb_gc_register_address(),
doesn’t it mean that we don’t need any mark function? We then just need
to rb_gc_unregister_address() when the C destructor is called.)

Regards,

Bill

···

Paul Brannan pbrannan@atdesk.com wrote:

You don’t really need references to all the inner the objects on the
stack; you could have a reference to an object that holds references to
all your inner objects.

But at any level, if that object that holds references to the inner
objects was not created using Data_Wrap_Struct(), there is no way for it
to mark the inner objects, is there?

I think so.

Actually, what is the meaning of “registering B”? Is it
rb_gc_register_address()? I am assuming here only the Top object is
created using Data_Wrap_Struct(). (If we use rb_gc_register_address(),
doesn’t it mean that we don’t need any mark function? We then just need
to rb_gc_unregister_address() when the C destructor is called.)

When I speak of creating an object, I mean allocating the memory for the
object’s data (when I think of an object, I think of a C++ object, not
the entity that the VALUE is pointing to).

When I speak of registering an object with the garbage collector, I mean
wrapping it with a Ruby object. The gargage collector then knows it is
there and knows that the object must at some point be freed.

It’s confusing, because there are two objects (the RObject and the
object that is being wrapped), and those objects act as a single unit.
I can use clearer wording if I have better words to use.

Paul

···

On Wed, Sep 25, 2002 at 11:43:01PM +0900, William Djaja Tjokroaminata wrote:

Paul Brannan pbrannan@atdesk.com wrote:

Hi Paul,

Thanks for the clarification. I guess then the actual problem may be even
more complicated than what has been discussed, as in my case, not all the
inner C struct’s are wrapped by an RObject (such as a struct that
contains a datum of type BigNum). (Yes, yes, probably I should have used
an “independent” C library that provides arbitrary-precision, hash,
etc…)

Regards,

Bill

···

============================================================================
Paul Brannan pbrannan@atdesk.com wrote:

But at any level, if that object that holds references to the inner
objects was not created using Data_Wrap_Struct(), there is no way for it
to mark the inner objects, is there?

I think so.

When I speak of creating an object, I mean allocating the memory for the
object’s data (when I think of an object, I think of a C++ object, not
the entity that the VALUE is pointing to).

When I speak of registering an object with the garbage collector, I mean
wrapping it with a Ruby object. The gargage collector then knows it is
there and knows that the object must at some point be freed.

It’s confusing, because there are two objects (the RObject and the
object that is being wrapped), and those objects act as a single unit.
I can use clearer wording if I have better words to use.

Paul

My mistake; I meant RData. But whether you have an RObject or an RData
or an RBignum or whatever, you still have an object that the garbage
collector knows about.

Paul

···

On Thu, Sep 26, 2002 at 02:03:12AM +0900, William Djaja Tjokroaminata wrote:

Hi Paul,

Thanks for the clarification. I guess then the actual problem may be even
more complicated than what has been discussed, as in my case, not all the
inner C struct’s are wrapped by an RObject (such as a struct that
contains a datum of type BigNum). (Yes, yes, probably I should have used
an “independent” C library that provides arbitrary-precision, hash,
etc…)