Purpose

An accepted convention for writing Ruby C extensions.

Reason

Too many C extensions with absoltely no correlation in terms of conventions.

Proposal

Ruby-specific things

Ruby methods

All Ruby methods should have the name format <class name>_<ruby method name>. So the initialize method of a class NDTypes would like so:

rb_define_method(cNDTypes, "initialize", NDTypes_initialize, 1);

Ruby singleton methods

Singleton method names should be prefixed by a s before the method name. For example, if you want to define a singleton foo inside a class Bar:

rb_define_singleton_method(cBar, "foo", Bar_s_foo, 1);

Ruby classes

The VALUE variable containing Ruby classes should be prefixed with a c. So if you’re defining a Ruby class NMatrix, it would look like so:

VALUE cNMatrix = rb_define_class("NMatrix", rb_cObject);

Ruby nested classes

If you have nested classes, the nested class name should come after the parent class, separted by an underscore. For example, to define a class Foo nested inside Bar:

VALUE cBar = rb_define_class("Bar", rb_cObject);
VALUE cBar_Foo = rb_define_class_under(cBar, "Foo", rb_cObject);

Ruby modules

Parsing keyword arguments to Ruby methods

Since there is no direct way for accessing kwargs via C extensions we advocate usage of

However, you should be mindful of this bug and avoid arg scanning in C for performance reasons.

C-specific things

General C function conventions

All functions should be defined as static.

bang and boolean methods

Ruby supports method names ending in bang (String#chomp!) and boolean methods ending in question mark (Array#empty?). The corresponding function in C will end with _bang and _qmark respectively.

Struct definitions

Struct definitions should always be done with a typedef. Nowhere in the code should you use the struct keyword for specifying a type. Example:

typedef struct {
  int x;
  float y;
} foo_t;

Default values for structs

Structs should be initialized to defaults with C99’s compound literal syntax. For example:

typedef struct {
  int x;
  float y;
} foo_t;

foo_t var = { .x = 44, .y = 55.0 };

Struct mark/free/size functions

Various functions required for GC marking, freeing and getting the size of structs should be written using the convention <struct name>_d<task name>. So for example, the mark function of type foo_t would be foo_t_dmark, foo_t_dsize and foo_t_dfree.

Defining structs for telling Ruby how to handle C structs

The latest Ruby requires you to set the parameters of a C struct of type rb_data_type_t that tells Ruby how to handle a particular C struct when it is encapsulated inside a Ruby object.

This must be declared as static const. The name of the struct must be postfix’d with _type in order to name the type. Here’s an example for a struct foo:

static const rb_data_type_t foo_type = {
  .wrap_struct_name = "foo",
  .function = {
    .dmark = foo_dmark,
    .dfree = foo_dfree,
    .dsize = foo_dsize,
  },
  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
};

Links:

  • https://github.com/ruby/ruby/blob/trunk/doc/extension.rdoc#c-struct-to-ruby-object

Macros

Macros should be ALL_CAPITAL_WITH_SNAKE_CASE.

C APIs

Some important features of C APIs that will be exposed to other extensions of other Ruby gems:

  • API functions or any indirect functions that they call should never raise Ruby errors.
  • Error conditions should be indicated by a numerical value. Ideally

Internal Ruby objects for C extensions

It is common to create some internal Ruby objects that only visible via C extensions for things like saving state between multiple Ruby objects. If you want to use these objects as a means of sharing data between multiple Ruby objects, you need take some precautions when working with the Ruby GC.

General organization of C files

Since C does not have namespaces, it becomes a little hard to keep track of data and the functions that act on the data. Therefore, it is advisable to keep structs and the important functions that act on the structs (like allocation, deallocation, marking, etc.) together for fast reference and reading of code.