A Comparison of Python and Ruby Extension Interfaces (Re: Comparison between Python and "Ruby")

Greg Ewing greg.ewing at compaq.com
Wed Nov 3 15:26:28 CET 1999


Martijn Faassen wrote:
> 
> From what I hear in this thread its C interfacing would also be interesting
> to compare with Python's, especially since Ruby uses garbage collection,
> which is something Python's looking at using in the future, in some
> way.

Okay, here are some thoughts following a brief time looking
at and comparing the "dbm" module implementations from Ruby
and Python.

The first observation is that the Ruby version is 13K in
size, whereas the Python version is only about 7.5K.
However, this is not a fair comparison, because the Ruby
version defines more methods.

Eyeballing the code, I must say that the Ruby version
generally looks neater and tidier. Some reasons for this
seem to be:

* The names of the Ruby interface routines are often
shorter than the equivalent Python ones.

* Checking types of arguments and raising errors seems to
be easier in the Ruby version, e.g. Ruby

    Check_Type(keystr, T_STRING);
    key.dptr = RSTRING(keystr)->ptr;
    key.dsize = RSTRING(keystr)->len;

vs. Python

    if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
        PyErr_SetString(PyExc_TypeError,
            "dbm mappings have string indices only");
        return -1;
    }

The Ruby version isn't all that much shorter, but it
looks neater. On the other hand, the Python version manages
to produce a more specific error message; if the Ruby
version did that too, it would be longer.

* Since Ruby has mark-and-sweep garbage collection, there
is no manipulation of reference counts. There weren't
actually any examples of this in the Python dbm module,
though.

* Ruby seems to be able to raise exceptions without
having to explicitly propagate them back out of routines,
which eliminates a lot of result testing and returning of
-1's and None's that goes on in Python extension code.

Some other observations, in no particular order:

* In Ruby, routines with a fixed number of arguments can
be defined so that they are received as separate C
arguments instead of a vector, e.g.

static VALUE
fdbm_store(obj, keystr, valstr)
    VALUE obj, keystr, valstr;

This doesn't actually save much code, however, since you
still have to test and convert each argument.

* Ruby's method of representing an extension type is a
whisker more complicated. Instead of allocating a single
object, you have to create an object of type DATA, which
contains a pointer to a class and a pointer to a C
structure.

* The mechanism for associating methods with object types
is somewhat simpler in Ruby. In Python, some methods live
in slots in the type object, while others live in a method
table or are somehow otherwise accessed through the getattr
method. In Ruby, all methods, including the ones for built
in operations, are attached to the object's class, which seems
to play the role of both the Python type object and method
table. The initialisation function of the Ruby dbm module
starts off like this:

void
Init_dbm()
{
    cDBM = rb_define_class("DBM", rb_cObject);
    rb_include_module(cDBM, rb_mEnumerable);

    rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1);
    rb_define_singleton_method(cDBM, "new", fdbm_s_open, -1);
    rb_define_method(cDBM, "close", fdbm_close, 0);
    rb_define_method(cDBM, "[]", fdbm_fetch, 1);
    rb_define_method(cDBM, "[]=", fdbm_store, 2);
    rb_define_method(cDBM, "indexes",  fdbm_indexes, -1);

etc. There is no need to declare and initialise a type object
or method table as in the Python version, which makes things
somewhat more direct and easier to follow.

Summary:

Ruby extension modules seem to be slightly easier to write and
read than Python ones. The main reasons for this are the lack
of reference counting, a less obtrusive exception propagation
mechanism, and a more uniform notion of types and classes.
There are also some minor conveniences, such as C methods which
take an ordinary argument list instead of a vector. The
broad approach to exension writing is, however, fairly similar
in both systems.

Tomorrow I may take a deeper look at how Ruby unifies types
and classes and see whether there is anything there that
Python could learn from.

Greg




More information about the Python-list mailing list