The best kittens, technology, and video games blog in the world.

Saturday, June 02, 2007

RubyC programming language

Sometimes I call her
There's a programming language in which Ruby and many Ruby libraries are written, but pretty much nothing else. Let's call it RubyC. It looks a lot like C, and can even be compiled by C compilers, but it's different in many important ways:

  • It is garbage-collected
  • All functions return one VALUE, and all their arguments are VALUEs
  • It supports many features of Ruby, usually with just some syntactic overhead. In particular Ruby standard library and object-oriented model are available
Here are a few RubyC snippets (slightly reformatted for better readability). This one implements Array#sort:
VALUE rb_ary_sort(VALUE ary)
ary = rb_ary_dup(ary);
return ary;

Notice that both the argument (from Ruby point of view ary is self), and the return value are VALUEs, and that it completely ignores memory management - freshly allocated result of rb_ary_dup is going to manage itself, somehow.

Here are a few more snippets. This one sets up Range class:
void Init_Range()
rb_cRange = rb_define_class("Range", rb_cObject);
rb_include_module(rb_cRange, rb_mEnumerable);
rb_define_method(rb_cRange, "initialize", range_initialize, -1);
rb_define_method(rb_cRange, "==", range_eq, 1);
rb_define_method(rb_cRange, "===", range_include, 1);
rb_define_method(rb_cRange, "eql?", range_eql, 1);
rb_define_method(rb_cRange, "hash", range_hash, 0);
rb_define_method(rb_cRange, "each", range_each, 0);
rb_define_method(rb_cRange, "step", range_step, -1);
rb_define_method(rb_cRange, "first", range_first, 0);
rb_define_method(rb_cRange, "last", range_last, 0);
rb_define_method(rb_cRange, "begin", range_first, 0);
rb_define_method(rb_cRange, "end", range_last, 0);
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
rb_define_method(rb_cRange, "inspect", range_inspect, 0);

rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);

rb_define_method(rb_cRange, "member?", range_include, 1);
rb_define_method(rb_cRange, "include?", range_include, 1);

id_cmp = rb_intern("<=>");
id_succ = rb_intern("succ");
id_beg = rb_intern("begin");
id_end = rb_intern("end");
id_excl = rb_intern("excl");

And this one implements Float#<=.
static VALUE flo_le(VALUE x, VALUE y)
double a, b;

a = RFLOAT(x)->value;
switch (TYPE(y)) {
case T_FIXNUM:
b = (double)FIX2LONG(y);

case T_BIGNUM:
b = rb_big2dbl(y);

case T_FLOAT:
b = RFLOAT(y)->value;
if (isnan(b)) return Qfalse;

return rb_num_coerce_relop(x, y);
if (isnan(a)) return Qfalse;
return (a <= b)?Qtrue:Qfalse;

I'm not going to describe it in detail, README.EXT in Ruby source distribution already does a pretty good job. I just think it's a pretty good language:
  • It's almost as fast as pure C
  • It is far easier to code than pure C, thanks to garbage collection, decent stdlib, and real OO (where real means something based on message-passing, no C++ crap)
  • It is far nicer than most similar languages like Perl's XS.
One of the few downsides is its threads-unfriendliness. I'm thinking about RubyC back-end for RLisp compiler. Compilation with gcc would be somewhat slow, but it would generate much faster code than now.

RubyC also offers pretty good performance/expressiveness trade-off - one can code performance-critical sections in C, the glue in RubyC, the high-level stuff in Ruby, and it would all work together well. At least it beats Java.

1 comment:

Sébastien said...

It's interesting to have a short insight into Ruby C runtime - I like the idea of using a slightly higher-level C to develop applications.

I'd also recommend having a look at Lua or Io runtimes, which are easy to use and quite efficient as well.