Compiling Ruby: From Text to Bytecode
engineyard.com
engineyard.com
Here is a question, is the 'slowness' of ruby because of its compiler/interpreter or is it because of its language design?
So, if I had to attribute 'slowness', I'd say it's because of the implementation (compiler/interpreter) instead of the language design
"Slowness" is subjective, but I think this answers your question.
There's also quite a bit of Ruby that's non-trivial to compile. For instance, think about method_missing. If a message gets sent to an object, a naive implementation would have to check every parent class up the inheretance chain, and then do it all over again to see if a method_missing is defined, too. That's quite a bit of time. Also, things like open classes make things like caching hard, as well.
None of these problems are insurmountable, but they take some work and some effort. Luckily, Ruby has those people now.
http://eigenclass.org/hiki/The+double+inclusion+problem
One problem that Ruby does need to deal with is when implementation problems become institutionalised as language specifications.
http://blog.jcoglan.com/2009/06/06/when-bugs-become-features...
Ruby should be taking the same route (PIC) that the Javascript VMs are. Perhaps this is planned for one of the Ruby VMs but I haven't heard anything along these lines yet.
You can actually do better in many cases, by using C++ style vtables which only requires an array lookup. The are two caveats with vtables for Ruby: Since all objects inherit from Object, all classes need a vtable large enough to hold all methods known at compile time, and secondly you need a fallback mechanism to handle method names not known at compile time. The size overhead is actually not necessarily so bad for typical apps - my compiler itself would have a vtable overhead of about 40K ("vasted" vtable slots) but the hash approach also have (smaller) overheads so the total amount of memory wasted is even lower.
You also need to handle re-definition of methods at compile time, but that's a simple matter of propagating the vtable change down the inheritance hierarchy until you reach the bottom or a subclass that has already overloaded the method (Prof. Michael Franz, who's one of the guys behind "trace trees" which is also gaining traction in the JS world wrote a report on using that method to add runtime interface - or protocol - changes to Oberon back in 93 I think). It makes dynamic method redefinition slower, but that's far more rare than dynamic method calls.
There are other parts that are trickier. You can redefine Fixnum for example, which means that you need to either do lots of analysis and have a fallback prepared, use type tagging (like MRI) or make integers actual objects. The alternatives are either difficult (analysis+fallback), bloats and slows your code (type tags and objects) and/or causes extra memory usage and pressure on your FC (making integers real objects).
You also have the "require" problem. A common Ruby idiom is to loop over a directory and require all files in it. Do you require it at compile time, or at runtime? Granted, that part is easier for a JIT (though even an ahead of time compiler for Ruby will need to include either a small VM or a JIT to handle eval and completely dynamic require/load's)
Not to mention the fun little issue of code executing in a class definition, meaning you don't actually even know what methods a class has without potentially executing code. Heck, for a really pathological case, more than one Ruby ORM establishes a database connection and executes queries in the class definition in order to add methods to the class then and there.
All of this makes Ruby really painful to compile efficiently since you know so little about the program without actually executing it.
At the moment I'm just focusing on getting attr_reader and friends working. Sounds simple, but since I wanted to write attr_reader and attr_writer mainly in Ruby it's a rabbit hole that required me to get basic parts of Symbol and String working, as well as define_method, fixing various method dispatch issues, fixing string interpolation and more; those changes will make up the bulk of the content of the next couple of parts I write. Once all those pieces are in place a lot of the rest of what's needed to compile a fairly decent subset of Ruby is pretty simple (though lots of gruntwork). With some luck (and enough spare time) I hope to get the compiler self-hosted by the end of the year.
http://techon.nikkeibp.co.jp/article/HONSHI/20090106/163620/
Ruby can be made a lot faster than current implementations, but the reasons it hasn't been made faster a long time ago is to a large extent down to the language design.
Now, how many of those decisions you could've made differently in order to get more performance without at the same time losing what makes Ruby so great to work with is another question...
http://blog.headius.com/2009/04/how-jruby-makes-ruby-fast.ht...
This post shows how if you turn off certain Ruby language features you can make it much faster. Then he shows how his Ruby-like but static language is much faster.
I especially like the link at the bottom of the post to the Rubinius book tour http://bit.ly/1wVU4 aka what you can read to fully understand or design a Rubinius.
Faster speed is always good. However, my interest in Rubinius is more of a learning thing. Its really cool to be able to check the implementation of class 'Class' http://bit.ly/fCyIw when you need to or fully understand how some underlying algorithms implemented in the language are put together in just plain old Ruby code (not C).