Slick As Ruby, But Way Faster

Crystal’s unmistakable Ruby flavor brings elegant, readable, and less verbose code. Crystal’s “Hello world” example (see hello_world.cr) is brief:

 puts ​"Hello, Crystal World!"​ ​# => Hello, Crystal World!

which prints a string to standard output. If you want it even shorter, use p, for printing any object:

 p ​"Hello, Crystal World!"​ ​# => "Hello, Crystal World!"

(If you want to follow along, see Installing Crystal on Your Machine).

You don’t need to put your code inside a class or starting from a main() function. It’s just one line!

Crystal is an ideal complement to Ruby: Crystal brings much greater performance in places where Ruby is in need of it, while Ruby can continue to play its highly dynamic role in other parts of an application. To compare performance, let’s compare a program that is the same in both Crystal and Ruby, and run it in both contexts.

A Fibonacci number is the sum of its two predecessors, except for 0 and 1, where it returns itself. This program calculates the sum of a series of Fibonacci numbers using a recursive algorithm, and is valid Ruby as well as Crystal code. The program calculates the Fibonacci numbers from 1 to 42 and adds them up in a variable sum, which is shown at the end. The actual calculation happens in the fib method.

 def​ ​fib​(n)
 return​ n ​if​ n <= 1
  fib(n - 1) + fib(n - 2)
 end
 
 sum = 0
 (1..42).​each​ ​do​ |i|
  sum += fib(i)
 end
 
 puts sum ​# => 701408732

The program is named fibonacci.cr, with .cr as the Crystal extension. (Ruby doesn’t mind.) Looking at the code of fibonacci.cr, you’ll only see Ruby idioms: variables without type indication, a familiar method definition, and the .each iterator over a range.

We’ll time its execution on the same machine: Ubuntu 16.04, 64-bit OS, AMD A8-6419 processor with 12GB of memory. The code isn’t highly tuned, but because the same code runs in both languages, it’s a fair basic comparison.

Let’s see how Ruby performs:

$ time ruby fibonacci.cr

 real 3m44.437s
 user 3m43.848s
 sys 0m0.048s

Luckily, I went for a coffee. Now here’s Crystal in its development mode:

$ time crystal fibonacci.cr

 real 0m12.149s
 user 0m12.044s
 sys 0m0.356s

Crystal performs the same task in 12s, including the build (compilation) time, a performance improvement of 18.5 times.

If you were going to use this program in a production environment, you’d make a release build:

$ crystal build --release fibonacci.cr

This generates an executable file called fibonacci, and looking at its execution:

$ time ./fibonacci

 real 0m10.642s
 user 0m10.636s
 sys 0m0.000s

you’ll notice an additional improvement, giving a relative speed improvement of 21 times over Ruby!

Not all Crystal code will run this much faster. But in general, you can expect a dramatic speed boost of 5 to 100 times compared to Ruby, while at the same time consuming much less memory. For other dynamic languages, the gain will be a bit smaller, but it will still be quite significant.

Here[8] is a comparison calculating fibonacci(45) in different languages on faster hardware:

LanguageVersionResult(s)
Cgcc 4.9.23.575
Crystalv0.20.16.981
Rust1.14.07.808
Juliav0.5.09.657
LuaJIT2.1.0-beta210.150
Gogo1.7.410.249
Node.jsv7.315.122

Crystal is compiled to native code, yet development speed isn’t hindered by that: you can run a project (even when it contains dependencies on other libraries) as simple as this:

$ crystal project.cr

This looks like an interpreter mode. Nevertheless, the source code was completely compiled to a temporary file containing native code and then executed. Remember: Crystal has no interpreter and no virtual machine.

So what then are the language differences between Ruby and Crystal that explain this huge performance gap? Crystal is compiled into executable code, and in order to do that, the compiler needs to know the types of all expressions in the code. But because it’s a smart compiler that figures out most types by itself through an inference algorithm, the compiler rarely requires you to annotate your code with types. However, you’re also very welcome to explicitly annotate your code with types to make your intentions clearer to both human readers and the compiler.

Crystal isn’t completely compatible with Ruby—it won’t run Rails, and it doesn’t (yet) have a complete equivalent to irb. But using almost all of Ruby’s idioms, it’s a close relative, so porting Ruby code to Crystal is quite straightforward. We’ve gathered the most relevant porting considerations in Appendix 2, Porting Ruby Code to Crystal.

Ruby also often offers you a choice between several methods that do exactly the same thing, like length, size, and count for Enumerable types, or map vs. collect and select vs. find_all. Crystal, going all the way for efficiency, adheres to a “single-way approach,” preferring size, map, and select in these cases.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.136.186