Ruby Interpreters: What You Need to Know

BY Derek Haynes

January 20, 2019

Using the right Ruby interpreter to run your programs can make all the difference. Unfortunately, it can be tough to find resources about different Ruby interpreter options, or about how to choose the right one.

Below, we’ve compiled a wealth of information about interpreters in Ruby. Even if you start this article asking "What is a Ruby interpreter?", you’ll learn exactly what you need to know to make the right decision.

programming.png

What is an Interpreter? Compiled vs. Interpreted Programming Languages

Languages are the foundation of communication. They consist of a standard set of vocabulary, grammar, and syntax that two people agree upon to exchange information. When two people don’t speak the same language, however, you need a way to translate or interpret the same ideas from one language to another.

The same concept of translation and interpretation applies to programming as well. Machines aren’t automatically able to comprehend the high-level code that humans program in. They can only execute machine code, a limited set of low-level instructions that the computer’s CPU can immediately understand.

Machines have two ways of working with programming languages like Ruby: compilation and interpretation.

Compiled programming languages require a tool called a compiler. Before the user can run a program, the compiler must convert the high-level code into a series of low-level instructions in a series of stages. This machine code is specific to the machine that the program is running on.

Interpreted programming languages require a tool called an interpreter. The interpreter converts the source code to machine code line by line, while the program is running.

This difference is like the distinction between translating and interpreting a foreign language. Translators do their work in advance, before the person who needs it will use it. Interpreters perform the translation live, while the person who needs it is listening.

Both compiled and interpreted languages have their pros and cons. Some languages such as Java use a mixture of both methods. In general, interpreted languages are more flexible, more portable to different systems, and easier to debug. However, they pay for these advantages by sacrificing speed and performance.

Compiled languages are typically faster than interpreted languages. This is because the compiler has the time it needs to optimize the code for the specific machine that the program is running on.

Although Ruby is more often interpreted, it can be both interpreted and compiled depending on the implementation. In the remainder of this article, we’ll discuss only interpreters for Ruby.

programmer.png

What is a Ruby Interpreter?

A Ruby interpreter is any program that is able to interpret source code written in the Ruby language.

Just like you might use different human translators or interpreters, there’s not a single version of the Ruby interpreter. Instead, there are multiple interpreter options for Ruby developers. Each version imparts a slightly different "flavor" to the language.

So how can you be sure that the interpreter you use is actually running the "real" Ruby? By using the Ruby Spec Suite (also known as ruby/spec). The Ruby Spec Suite is a set of tests to verify that a given Ruby implementation has the correct behavior and results when interpreting a program.

Ruby Interpreter Options: YARV, Ruby MRI, JRuby, and Rubinius

Below, we’ll discuss the most popular alternatives for Ruby interpreters: YARV, Ruby MRI/CRuby, JRuby, and Rubinius. All of the interpreters below have passed the Ruby Spec Suite and are solid, mature options for running Ruby code.

YARV

YARV (Yet Another Ruby VM) is the stack-based interpreter technology that powers the official interpreter of Ruby. Beginning with Ruby version 1.9, YARV has replaced the old version of Ruby MRI (also known as CRuby). As of Ruby 2.6, YARV remains the official interpreter technology used for Ruby.

When you run a Ruby program, YARV translates the code to a limited instruction set that can run in the Ruby virtual machine (VM). A VM is a program running on your computer that emulates a separate computer to have better predictability and stability. This ensures that all computers can run Ruby regardless of the specific machine code they use.

Ruby MRI/CRuby

Before YARV arrived in Ruby 1.9, the default Ruby interpreter was Ruby MRI, also known as CRuby. Ruby MRI stands for Matz’s Ruby Interpreter (named after "Matz," or Yukihiro Matsumoto, the chief designer of Ruby).

The alternative name, CRuby, reflects the fact that the interpreter is in the C programming language. CRuby differs from YARV under the hood: whereas YARV uses a stack to parse Ruby code, CRuby uses an abstract syntax tree.

JRuby

Just as CRuby was in C, JRuby is a Ruby interpreter in the Java programming language. JRuby follows in the footsteps of other programming languages that run atop the Java Virtual Machine (JVM), such as Clojure and Scala.

Because JRuby uses the JVM, you can run Ruby programs anywhere that you can run Java programs, from laptop computers to Android phones. JRuby can also leverage Java standard and third-party libraries.

Rubinius

Rubinius is an attempt to interpret Ruby programs as little C code as possible, differentiating itself from Ruby MRI/CRuby. The foundations of Rubinius are in the C++ programming language, while other parts use as much Ruby code as possible.

Rubinius includes a "Just In Time" (JIT) compiler that compiles the code while the program runs, helping it to run more dynamically. This gives it improvements over Ruby MRI in terms of memory management and speed.

Which Ruby Interpreter Should You Use?

The matter of which Ruby interpreter to use is an open-ended question that depends on your specific situation.

If you’ve installed the default version of Ruby, then you’re almost certainly using YARV (if Ruby 1.9 and above) or Ruby MRI (if Ruby 1.8 and below). In many cases, this default option is sufficient for Ruby developers.

However, Rubinius or JRuby may be better if you have high-performance requirements from your Ruby programs. According to one benchmark test, Rubinius and JRuby achieved performances roughly twice as good as Ruby MRI.

Another consideration for which Ruby interpreter to use is the question of threads and parallelism. Ruby MRI uses a feature known as the Global Interpreter Lock (GIL). The GIL prevents multiple program threads from accessing the same data at the same time. By default, Ruby is single-threaded and does not allow for parallelism and multithreading.

However, this restriction is not present in other implementations of the Ruby interpreter, such as Rubinius and JRuby. You can take full advantage of multi-core and multi-CPU systems, significantly boosting performance.

The good news is that the Ruby team wants to bypass the limits of the GIL in the upcoming Ruby 3 release via a mechanism known as Guilds. In the future, you might be able to see some benefits of parallelism and multithreading in the default version of Ruby. However, you’ll have to be patient enough to wait for Ruby 3 (currently without a release date),

laptop.png

Final Thoughts

The alternatives listed above are by no means your only options for Ruby implementations. mruby is a Ruby implementation intended for embedded systems such as the Raspberry Pi. Meanwhile, Opal is a compiler that converts Ruby to JavaScript.

For most Ruby use cases, though, you can’t go wrong by choosing one of the following: