Keeping it Small and Simple

2008.01.23

Getting started with Rubinius

Filed under: Ruby Programming — Tags: , , — Lorenzo E. Danielsson @ 03:06

According to the web site, Rubinius is:

Rubinius is a project to develop the next generation virtual machine for the Ruby programming language.

Of course there is some more information about it, but I’m not going to yank and put all of it. Go to the site and read for yourself. This is still a young project so don’t expect your Ruby scripts to just work. But it’s still worth installing it and toying around with it. If you find issues, you can always help out by filing bug reports.

Installing

Pretty much a no-brainer. If you don’t want to use git you can get a tarball here. First.


% cd ~/tmp
% tar zxf ~/dl/rubinius-daily-current.tar.gz

Of course, you’ll have to replace ~/dl with the directory you downloaded to. Also, I extracted it into ~/tmp, but you are of course free to choose where you want it extracted. Once you have extracted the archive, cd rubinius-daily and read the INSTALL file and make sure you have all the dependencies installed. Then issue:


% rake build
% su
# rake install

There, that didn’t hurt, did it? Now you should have Rubinius installed as /usr/local/bin/rbx. You will also have the Rubinius modules in /usr/local/lib/rubinius/. It's probably a good idea to start off by looking at what modules are there. That will give you an idea of what you can and cannot do. You will notice that there are some modules missing, if you compare to your Ruby module directory. You will also notice that Rubinius has added some modules of its own.

Trying it out

Now you are ready to put Rubinius to the test. I started out with something very simple.


 1 #! /usr/bin/ruby
 2
 3 # Print command-line arguments.
 4 #
 5 # Author: Lorenzo E. Danielsson
 6 # Date created: 2008.01.23
 7
 8 abort "You called #{$0} without any command line arguments." if ARGV.empty?
 9
10 puts "You called #{$0} with #{ARGV.length} arguments:"
11 ARGV.each { |arg| puts "  * #{arg}" }

Then I tried it out:

% ls
args.rb
% rbx args.rb foo bar
You called args.rb with 2 arguments:
* foo
* bar
% ls
args.rb args.rbc
% rbx args.rbc foo bar
You called args.rbc with 2 arguments:
* foo
* bar

Notice that after I ran the script the first time, I now have an args.rbc file. Once the Ruby script has been compiled, I can pass the byte-code compiled program to rbx and it works just as well.

Next test: readline, since:

% ls /usr/local/lib/rubinius/0.8/readline*
/usr/local/lib/rubinius/0.8/readline-native.rb
/usr/local/lib/rubinius/0.8/readline-native.rbc
/usr/local/lib/rubinius/0.8/readline.rb
/usr/local/lib/rubinius/0.8/readline.rbc

Here is my trivial program, which work fine in Ruby (as in Matz' Ruby, cRuby, or whatever the name-of-the-day is):


 1 #! /usr/bin/ruby
 2
 3 # Complete month names.
 4 #
 5 # Author: Lorenzo E. Danielsson
 6 # Date created: 2008.01.23
 7
 8 require 'readline'
 9
10 months = %w[ January February March April May June July August September
11 October November December ]
12
13 Readline.completion_proc = Proc.new { |str|
14   months.find_all { |m| m =~ /^#{str}/ }
15 }
16
17 puts <<EOH
18 Enter the names of months to get their ordinal numbers.
19 Enter 'quit' or 'exit' to quit this program.
20 EOH
21
22 loop do
23   inp = Readline.readline('-- ', true).strip
24   next if inp.empty?
25   break if %w[ quit exit ].include? inp
26
27   case months.include? inp
28   when true
29     puts "#{inp} is month number #{months.index(inp) + 1}."
30   when false
31     puts "Not a month: #{inp}"
32   end
33 end

Things started well:

% rbx months.rbc
Enter the names of months to get their ordinal numbers.
Enter 'quit' or 'exit' to quit this program.
-- J [TAB,TAB]
January July June
-- January
January is month number 1.

To get January to complete, I only added an 'a' and pressed TAB, just like you would expect from readline. Now what happens if I hit TAB without having typed any letters? Well, in Ruby it shows a list of all available completions, as shown below:

% ruby months.rb
-- [TAB*2]
April December January June May October
August February July March November September
--

So I tried this in Rubinius as well. The result:

% rbx months.rbc
Enter the names of months to get their ordinal numbers.
Enter 'quit' or 'exit' to quit this program.
-- *** glibc detected *** rbx: free(): invalid next size (fast): 0x081107d0 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6[0xb7d59735]
/lib/i686/cmov/libc.so.6(cfree+0x90)[0xb7d5d1a0]
/lib/libreadline.so.5[0xb6e9a6fe]
/lib/libreadline.so.5(rl_complete_internal+0x118)[0xb6e9c848]
...
...
[More output]

Ouch! Moreover my terminal was completely dead after this. Oh, well, just close it and launch a new one. Rxvt windows are like soooooooo cheap.. 😉

As I said earlier, don't expect things to work perfectly. By trying all kinds of things out, and reporting bugs when they occur, you can help to make Rubinius better. And to be fair, I'm on a mixed etch/lenny/sid system, so this doesn't *have* to be a Rubinius problem..

I wasn't quite done with my testing yet. I wanted to try to see if I could pull a module from /usr/lib/ruby/ and get it to compile with Rubinius and then write a simple test script. I chose ping.rb, for no other reason than that it does not exist as a Rubinius module.

First, I compiled it:

% cp /usr/lib/ruby/1.8/ping.rb .
% rbx ping.rb
% ls
ping.rb ping.rbc

So far so good. Next, for the test script:


 1 #! /usr/bin/ruby
 2
 3 # Check if hosts are up.
 4 #
 5 # Author: Lorenzo E. Danielsson
 6 # Date created: 2008.01.23
 7
 8 require 'ping'
 9
10 abort "No host to check." if ARGV.empty?
11
12 ARGV.each do |host|
13   puts "Host #{host} is #{Ping.pingecho(host) ? 'up' : 'down'}"
14 end

I compiled that as well:

% rbx pinghosts.rb
No host to check.

The message comes from the fact that rbx compiles and runs the program. I didn't pass in any hosts. Let's give a real try, shall we?

% rbx pinghosts.rb 127.0.0.1
*** glibc detected *** rbx: double free or corruption (!prev): 0x081829d0 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6[0xb7d8c735]
/lib/i686/cmov/libc.so.6(cfree+0x90)[0xb7d901a0]
/usr/local/lib/librubinius-0.8.0.so(XFREE+0x1d)[0xb7f2abcd]
/usr/local/lib/librubinius-0.8.0.so(cpu_event_clear_channel+0xa7)[0xb7eca117]
/usr/local/lib/librubinius-0.8.0.so(cpu_thread_exited+0x7f)[0xb7efd50f]
/usr/local/lib/librubinius-0.8.0.so(cpu_perform_system_primitive+0xe3)[0xb7ee93a3]
...
...
[ Lots more where this came from]

Oops.. Oh well, at least it compiled. And, you get good stack traces, so if you are so inclined, you can start following the Yellow Brick Road.

Conclusion

It's a bit hard to say much about Rubinius after having played around with it for a single evening. But it was a fun way to spend an evening and I'll be keeping 1.73 eyes on it. I think Rubinius can be a really neat addition to the Ruby family. Tomorrow I'll spend some time and actually read up on Rubinius internals a little.

These are interesting times for Ruby: 1.9 with YARV, Rubinius and of course JRuby. What next? Ruby for VIC-20? 😀

Advertisements

2 Comments »

  1. Ah, was wondering. Will Rubinius reduce the size of normal .rb script and will it make it behave like Java in that once the bytecode is obtained, it can be run on any Rubinius installation. If the answer to that one is yes, that why not just stick to the interpreter ?

    Comment by bbaka — 2008.01.23 @ 10:06

  2. Actually, the .rbc files are larger than the Ruby source files. They are compiled into byte codes and run in a VM, just like Java.

    There is a lot of work being done to make Ruby faster. As Ruby moves into more and more areas, scalability does become an issue (just ask Twitter). Also, if Ruby were faster, it would help the performance of rubygame and other similar libraries.

    Ruby itself got a VM recently, which is included in Ruby 1.9 called YARV. That is great. Rubinius is also trying to build their own virtual machine for Ruby. Hopefully the two teams can learn some optimization tricks from each other. They may also have slightly different goals.

    And remember that there are other Rubies that run in VMs as well, like JRuby. I hear there is some form of Ruby.Net as well, but aptitude search doesn’t give any results. Perhaps not in Debian yet, IOW.

    The possible danger would be that we get a bunch of different Ruby virtual machines unable to read each others’ byte codes. That is a non-issue as of yet, since Rubinius still can not be used for anything beyond trivial programs.

    I don’t intend to stop using ruby in favor of rubinius. But I program in Ruby and therefore interested in Rubinius and what it has to offer. For that reason, I will experiment with it.

    Comment by Lorenzo E. Danielsson — 2008.01.23 @ 12:57


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.