This first part aims at explaining how Ruby in the background is not Ruby anymore. In the next part I’m going to talk about HOW to bridge some existing C library with your ruby application.
As you might know already, the official ruby interpreter is written in pure C. This means that whenever you type a ruby instruction, the interpreter will call the corresponding C function for you. For example, if you do :
arr = Array.new
Ruby will call a C function (probably rb_ary_new) and a C structure will be created to hold the content of arr. When you will try to access arr later in your code, the interpreter will use that same C structure.
On the ruby side of things we say that everything is an object. On the C side of things we say that everything is a VALUE
You also already know that everything in ruby is an object. To represent this reality on the C side of things, a custom type (typedef) has been created and has been given the name of VALUE. This type is a pointer (well, in fact it is not really a pointer but we won’t go into this right now) that can reference any kind of data type. When C defines something as a VALUE, you know that it is dealing with something that either A) comes from the ruby side of things, B) will be returned to the ruby side of things or C) is usable on the ruby side of things in one way or another. In all other situations, C is just C and doesn’t need the VALUE data type. When you see C using VALUE, what you are really seeing is ruby from the inside, and ruby from the inside is an ugly beast. It is not pretty, not elegant, not easy, not cool and honestly not that interesting. The thing is, it can save you a lot of work if you want to bridge an existing C library into your ruby application instead of having to rewrite the whole thing in plain ruby. That, in part, is why it can be very useful to know a little bit of ruby’s ugly side.
Let’s move on. We said that VALUE was the C way to represent a ruby object. If you open one of the source file of the ruby interpreter (array.c, string.c, etc.), you will find that the word VALUE is used everywhere :
VALUE rb_do_stuff(VALUE param1, VALUE param2) {
VALUE some_variable;
int x;
//bla bla bla bla
return some_variable;
}
Since everything in ruby is an object (or a VALUE), the C functions that are responsible of returning something ready to use on the ruby side of things always have to return a VALUE. If they would return something else (int, char, char *, long), ruby would complain because it can understand objects and only objects.
A Fixnum is not a int, it is a VALUE. A Bignum is not a long, it is a VALUE. A String is not a char *, it is a VALUE, and so on.
VALUE is not really a pointer, you say?
Ok the following is not really important for the sake of this post but if you’re curious it will interest you. I said earlier that VALUE wasn’t really a pointer. Time has come to explain what it is and why. VALUE is in fact an unsigned long.
There is only one reason why VALUE is an unsigned long and not a pointer : efficiency.
Remember what a pointer is? It is a variable that contains an address to some structure in memory. It is perfect for complex objects like arrays, hashes and custom objects… but it is a bit overkill for more primitive objects like Fixnums, booleans (TrueClass and FalseClass instances) and nil (NilClass instance). Ruby inventor thought that it would be great if in some cases the VALUE object could BE the data instead of POINTING TO the data. I mean, why having a VALUE that points to a structure that contains an integer that contains the number 1 when you could simply have a VALUE that contains the number 1?
So instead of being a pointer, VALUE is an unsigned long that can contain either A) an address to some structure that contains the data or B) the data itself (immediate value).
The data in a VALUE is stored in such a way that it is possible to know if it contains an address to some structure in memory or an immediate value. Ingenious, ain’t it?
In my next post, I will try to explain how you can use the ugly side of ruby to bridge an existing C library into your ruby (or rubyonrails) application.
Great post. I’m waiting for the next parts.
Interesting post, I can’t wait for the next one.
Very nice explanation Frank! I had lots of trouble explaining this in a simple way, but you did it!
Thanks guys I’m glad you liked the post! I’ve been working on that kind of stuff recently and I realized that there wasn’t a lot of info on the subject.
I learned a lot, thanks!
Why not use ffi? or at least mention it.
I don’t know much of this extension. Why don’t you write a post about it instead?
In addition to ffi, there’s also Ruby/DL: ttsky.net/ruby/ruby-dl.html
Nice intro, waiting for the second part. Is ffi still experimental or slower than writing a c ext?
Great look in depth !
Insightful.
Can has part 2 now? plzkthx ;D
FFI is definitely the way to go for adapting a library.
Mike, haha 🙂 Never again will I put “Part 1” in a post title…
I really intended to follow through with the second part but I never had the time. I swear one day it will come out… and hopefully people will still find it useful.
Give us more 🙂
This problem should indeed be simply because he / she talked about. Exactly why the particular unexpected disappearance in shoeprint the application?|Still|Yet|However|Though|And yet} Chloe Bao Xin equally recognize that like take on basic from the same exact united states,Suddenly your gentle figure gazed Lilin in|Playing with|Using|But also from|However in|In|Exploiting|Employing|But also in} that element plus brimming an entire urban center on the blade suggests darkness.|Still|Yet|However|Though|And yet} no for that reason have an effect on the particular pass of one’s from the petrol Well-liked Chloe carrier induction model. Drunkard is your numerous vacationer right, Discipline purses Discipline purses Several at this point or perhaps way up, If ever the outdated housekeeper are able to see mood.