Wrapping a C Library: Allocation and duplication issues

I'm writing a wrapper for a C library [1] written in a very object
orientated style. All of the "classes" are created with a
librdf_new_classname method which acts almost the same as Ruby's
Class#new.

The problem I'm having is cleanly separating allocation from
initialization. Since most of the class construction functions require
arguments to initialize the object, I can't define separate alloc and
initialize functions.

The only option I see is to use Ruby 1.6 style code and define a
Klass.new method for my classes. The problems with this is it prevents
clean subclassing and object cloning. Is there a better way to wrap the
library?

Thanks,
Justin

[1] http://librdf.org/

···

--
Posted via http://www.ruby-forum.com/.

Justin Bonnar wrote:

I'm writing a wrapper for a C library [1] written in a very object orientated style. All of the "classes" are created with a librdf_new_classname method which acts almost the same as Ruby's Class#new.

The problem I'm having is cleanly separating allocation from initialization. Since most of the class construction functions require arguments to initialize the object, I can't define separate alloc and initialize functions.

The only option I see is to use Ruby 1.6 style code and define a Klass.new method for my classes. The problems with this is it prevents clean subclassing and object cloning. Is there a better way to wrap the library?

Thanks,
Justin

[1] http://librdf.org/

What about calling librdf_new_classname() from the initialize method, and not doing anything special in the alloc function?

README.EXT says:

To define and undefine the `allocate' class method,

  void rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE klass));
  void rb_undef_alloc_func(VALUE klass);

func have to take the klass as the argument and return a newly
allocated instance. This instance should be empty as possible,
without any expensive (including external) resources.

The ary_alloc function for Array, for example, does not allocate storage for the actual C array of VALUE. It only allocates the basic RArray object, with a null ptr. Then rb_ary_initialize() looks at the arguments and allocates storage for ptr, as needed.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Just curious: Are the Ruby bindings that come with Redland just not
suitable for your project? I'm wondering why you're re-inventing the
wheel here.

···

On 9/12/06, Justin Bonnar <jbonnar@berkeley.edu> wrote:

I'm writing a wrapper for a C library [1] written in a very object
orientated style...

I don't think that approach will work: librdf_new_classname() allocates
the memory it needs and returns a pointer to the structure. Part of the
problem is that struct may be different depending on the arguments
passed in (a particular storage backend, etc) and that the C header
files don't define the internals of the structures themselves (so I get
incomplete type errors during compilation.

-Justin

···

--
Posted via http://www.ruby-forum.com/.

Acutally, I'm not a C or Ruby/C guru, but would any of the following be
possible?

- Wrapping a null pointer in the allocation function, and then modifying
the DATA object to use the pointer returned by the
librdf_new_classname() call.

- Creating a pointer to the data structure, and then setting it's value
to the pointer returned by the librdf_new_classname() call.

The following code compiles and runs, but doesn't seem to work correctly
(other functions that access the C structure wrapped by the object
behave strangely.)

  static VALUE URI_alloc(VALUE klass)
  {
    librdf_uri* uri;
    return Data_Wrap_Struct(klass, 0, librdf_free_uri, uri);
  }

  static VALUE URI_initialize(VALUE self, VALUE uri_string)
  {
    librdf_uri* uri;
    Data_Get_Struct(self, librdf_uri, uri);
    uri = librdf_new_uri(World, StringValuePtr(uri_string));
    return self;
  }

Thanks,
Justin

···

--
Posted via http://www.ruby-forum.com/.

The following code compiles and runs, but doesn't seem to work correctly
(other functions that access the C structure wrapped by the object
behave strangely.)

Look at ruby-1.8.5/ext/dbm/dbm.c, in the ruby source, to see an example
how you can do this (fdbm_alloc(), free_dbm() and fdbm_initialize())

Guy Decoux

ts wrote:

Look at ruby-1.8.5/ext/dbm/dbm.c, in the ruby source, to see an example
how you can do this (fdbm_alloc(), free_dbm() and fdbm_initialize())

Thanks, this is exactly what I was looking to due.

Lyle Johnson wrote:

Just curious: Are the Ruby bindings that come with Redland just not
suitable for your project? I'm wondering why you're re-inventing the
wheel here.

The RDF-Redland binding is outdated and decidedly un-ruby-like. The
other problem is the SWIG binding for Redland doesn't expose all of the
functions I wanted to access. In addition to wrapping Redland I need to
get at some of the lower level functions from Rasqal.

We're also planning on building an Ontology-aware level above Redland,
with goals similar to that of the (now-defunct) Semitar project and want
to get the lowerlevel code right before working on that. Mixing the
existing binding with higher-level C code would be a little ugly - we'd
prefer to keep the lower level code in C.

-Justin

···

--
Posted via http://www.ruby-forum.com/\.

Cool. I hope that you'll share when you're done. :wink:

···

On 9/13/06, Justin Bonnar <jbonnar@berkeley.edu> wrote:

The RDF-Redland binding is outdated and decidedly un-ruby-like. The
other problem is the SWIG binding for Redland doesn't expose all of the
functions I wanted to access. In addition to wrapping Redland I need to
get at some of the lower level functions from Rasqal.

We're also planning on building an Ontology-aware level above Redland,
with goals similar to that of the (now-defunct) Semitar project and want
to get the lowerlevel code right before working on that. Mixing the
existing binding with higher-level C code would be a little ugly - we'd
prefer to keep the lower level code in C.