rocaml allows you to write Ruby extensions in Objective Caml.

I never seem to manage to release things when I should, so here’s a

pre-release announcement to let you know about this so you can play with

it

before the actual release, which could take longer than necessary.

```
http://eigenclass.org/repos/rocaml/head/
```

Young as it is, rocaml is very usable and the generated extensions are

reliable, since they enforce type safety and handle exceptions both

in Ruby and OCaml (OCaml exceptions are passed to Ruby).

Developing Ruby extensions with rocaml is easier and more convenient

than

writing a plain old C extension since rocaml performs Ruby<->OCaml

conversions

for a wide range of types, including abstract types and arrays, tuples,

variants and records of values of any supported type (e.g. arrays of

arrays of

variants of tuples of …).

Making an extension with rocaml involves two steps:

- implementing the desired functionality in Objective Caml, and

registering

the functions to be exported

(using Callback.register : string -> 'a -> unit) - creating the extconf.rb file (just modify the sample extconf.rb

distributed

with rocaml) defining the interface of your Objective Caml code.

** At no point is there any need to write a single line of C code when

**

** using rocaml.

**

# The mandatory trivial example

Let’s create an extension with a ‘fib’ function.

Here’s the OCaml code:

let rec fib n = if n < 2 then 1 else fib (n-1) + fib (n-2)

let _ = Callback.register “Fib.fib” fib

Here’s the interface declaration in your extconf.rb:

Interface.generate(“fib”) do

def_module(“Fib”) do

fun “fib”, INT => INT

end

end

That’s it. Running extconf.rb will generate all the required wrappers

and

make will link them against your ml code, creating a normal Ruby

extension

that can be used simply with

require ‘fib’

p Fib.fib 10

# Set of strings using a RB tree

Here’s a simple set based on an RB tree, specialized for strings (see

examples/tree for how to create several classes from a single

polymorphic

structure). The (unoptimized) RB tree takes only ~30LoCs, but lookup is

3X

faster than with RBTree, which takes >3000 lines and over ~250 lines for

the

equivalent functionality, without counting the *manually written*

wrappers for

the underlying C data structure.

This shows how rocaml handles complex types, including variant and

recursive

types.

Given this interface definition:

Interface.generate(“tree”) do

string_tree_t = sym_variant(“string_tree_t”) do |t|

constant :Empty

non_constant :Node, TUPLE(t, type, t)

end

def_class(“StringRBSet”) do |c|

t = c.abstract_type

fun “empty”, UNIT => t, :aliased_as => “new”

fun “make”, string_tree_t => t

```
method "add", [t, STRING] => t
method "mem", [t, STRING] => BOOL, :aliased_as => "include?"
method "dump", t => string_tree_t
method "iter", t => t, :aliased_as => "each", :yield => [STRING,
```

UNIT]

end

end

You can use the generated extension as follows (you can find the OCaml

code

below):

require ‘tree’

set = StringRBSet.new

set2 = s.add “foo” # the RB set is a functional, i.e. persistant

# data structure

# see how rocaml handles conversions for recursive variant types

p s.add(“foo”).dump

p s.add(“foo”).add(“bar”).dump

The above will print

[:Node, [:B, :Empty, “foo”, :Empty]]

[:Node, [:B, [:Node, [:R, :Empty, “bar”, :Empty]], “foo”, :Empty]]

showing you the structure of the RB tree.

That’s it for now, enjoy.

Further updates on eigenclass.org.

PS:

For the sake of completeness, here’s the OCaml code. You can find the

full

example in examples/tree.

exception Found

module RBSet =

struct

type color = R | B

type 'a t = Empty | Node of color * 'a t * 'a * 'a t

let empty = Empty

let rec mem x = function

Empty -> false

| Node(_, l, y, r) ->

if y < x then mem x l else if y > x then mem x r else true

let balance = function

B, Node(R, Node(R, a, x, b), y, c), z, d

| B, Node(R, a, x, Node(R, b, y, c)), z, d

| B, a, x, Node(R, Node(R, b, y, c), z, d)

| B, a, x, Node(R, b, y, Node(R, c, z, d)) -> Node(R, Node(B, a, x,

b), y, Node(B, c, z, d))

| (c, a, x, b) -> Node (c, a, x, b)

let add x t =

let rec ins = function

Empty -> Node(R, Empty, x, Empty)

| Node(color, a, y, b) ->

if x < y then balance (color, ins a, y, b)

else if x > y then balance (color, a, y, ins b)

else raise Found

in try match ins t with

Node (_, a, y, b) -> Node(B, a, y, b)

| Empty -> assert false (* ins always returns Node _ *)

with Found -> t

let rec iter f = function

Empty -> ()

| Node(_, l, x, r) -> iter f l; f x; iter f r

end

external intset_yield : int -> unit = “IntRBSet_iter_yield”

external stringset_yield : int -> unit = “StringRBSet_iter_yield”

let identity x = x

open Callback

let _ =

let def_set t =

let r name f = register (t ^ “RBSet” ^ “.” ^ name) f in

r “empty” (fun () -> RBSet.empty);

r “add” (fun t x -> RBSet.add x t);

r “mem” (fun t x -> RBSet.mem x t);

r “dump” identity;

r “make” identity;

in

List.iter def_set [“Int”; “String”];

register “IntRBSet.iter” (RBSet.iter intset_yield);

register “StringRBSet.iter” (RBSet.iter stringset_yield);