Do you love Ruby? Do you wish there was a better version of Ruby with blazing-fast performance like C? Well, your prayers have been answered. Let me introduce you to Crystal. The internet is calling it “Slick as Ruby, fast as C”.
Since its inception, developers have loved the Ruby programming language for its simplicity, focus on developer satisfaction, and productivity.
Ruby (and the Rails framework) has given rise to some of the legendary startups of the past decade, including Twitter, Github, AirBnB, Shopify, Soundcloud, and many more.
However, the main drawback of Ruby is performance and scalability. Being an interpreted language, Ruby is not as performant as C/C++, Rust, and Go.
Although not impossible, it is hard to scale a Ruby on Rails application. Moreover, the lack of static types in Ruby makes it hard to refactor code as the development team grows. Crystal, on the other hand, comes with all the good parts of Ruby but none of its drawbacks.
✔️ Crystal has beautiful syntax like Ruby
✔️ Crystal’s performance is comparable to C
✔️ Crystal supports native C bindings
✔️ Static Types and powerful macros for metaprograming
✔️ Crystal has Rails and Sinatra like web frameworks
Crystal’s syntax is almost identical to Ruby’s.
You will be able to write Ruby code directly in Crystal shell and vice versa. Like Ruby, Crystal is focused on keeping developers happy and productive. Ruby developers feel right at home with Crystal syntax. Take this example for instance (a Fibonacci series function 🌀):
def fib(n) if (n<=2) return 1 else return (fib(n-1) + fib(n-2)) end end
This code snippet is identical for both Ruby and Crystal. Due to the similar syntax, it is an absolute breeze to migrate from one to the other.
Installing Crystal and setting up your development environment is also very straightforward. You can install Crystal with a couple simple commands in any Linux distro or Mac. Take a look at the official guide here. However, you need to install a Linux subsystem to run Crystal on windows. I suggest Ubuntu 18.04 or higher.
In most benchmarks, Crystal performs better than Go, Python, and Node.js. Below are a couple links that compares Crystal’s performance with other programming languages:
🚆 👉 performance benchmark
🚆 👉 performance comparison
Crystal is built on top of the LLVM framework. This is the secret behind Crystal’s blazing performance. LLVM is the same framework that compiles C/C++ code to byte code.
With Crystal, you can effortlessly bind to your existing C libraries and code. This allows developers to handle low-level tasks in the application with native C libraries, further boosting performance.
Here’s an example of how to do C binding with Crystal.
Let’s say we have the following simple function written in C:
#include <stdio.h> void hello(const char * name){ printf("Say Hello %s!\n", name); }
First, we can compile this with gcc -c hello.c -o hello.o
, and then call it inside a Crystal script, like below:
#hello.cr @[Link(ldflags: "#{__DIR__}/hello.o")] lib Say fun hello(name : LibC::Char*) : Void end Say.hello("to đź”®")
One of the awesome features of Crystal is its static type system. It helps developers catch bugs in compile time. Dynamically typed languages such as Ruby and Python allow developers to write code with ease and deliver features quickly. However, over time as our code base and the team grows, it becomes harder to refactor and maintain this code.
Well, Crystal has a unique solution to this problem.
You can write code in Crystal just like any dynamically typed language. The compiler will only complain and require you to explicitly specify types in cases of ambiguity.
Let’s take a look at the web frameworks available for Crystal. If you like Rails or Phoenix, then you will love the Amber framework for Crystal.
Amber is built around the same philosophy of Rails (convention over configuration). Another promising framework is Lucky, also inspired by Rails. Both of these frameworks have an amazing documentation and a community of passionate developers actively contributing to the code base.
On the other hand, if you are a fan of lightweight web frameworks like Flask, Express.js (Node.js), and Sinatra, then take a look at Kemal. Still not convinced?
Well, take a look at these performance benchmarks for web frameworks. Crystal frameworks perform very well compared to other web frameworks, and the response time for Crystal’s frameworks is in the sub milliseconds.
Crystal has a powerful macro system for metaprogramming. It can be used for a range of things such as basic templating, AST inspection, types inspection, and running arbitrary external programs. [source: https://crystal-lang.org ]
Take this code snippet for instance. We can generate modules, classes, and structs with this simple function:
macro define_class(module_name, class_name, method, content) module {{module_name}} class {{class_name}} def initialize(@name : String) end def {{method}} {{content}} + @name end end end end # This generates: # module Foo # class Bar # def initialize(@name : String) # end # # def say # "hi " + @name # end # end # end define_class Foo, Bar, say, "hi " p Foo::Bar.new("John").say # => "hi John"
You can find out more about Crystal macros following this link.
Crystal uses something called fibers to achieve concurrency. Fibers are similar to operating system threads, but lightweight. Executing is managed internally by the process. A program can spawn multiple fibers, and Crystal will execute them efficiently to optimize performance.
Fibers are very similar to Go Routines. Here’s an example for spawning a fiber:
spawn do # ... socket.gets # ... end spawn do # ... sleep 5.seconds # ... end
[source: https://crystal-lang.org/reference/guides/concurrency.html]
Crystal allows communication of data between different fibers without having to share memory or worry about locks. Crystal does this with channels, which are inspired by CSP (Communicating Sequential Process)
How about Parallelism?
Currently Crystal doesn’t support parallelism. However, the team is working to get this feature into the stable version.
If you are curious and want to geek out, feel free to read the crystal documentation on concurrency models.
If you’ve been developing software for some time, you already know that every piece of technology has its limitations. The main drawback for Crystal is that it is the new kid in the block. Many consider Crystal and its ecosystems to be immature and not production ready.
While this is true to some extent, it also opens up the possibility of you being ahead of the herd to adapt to this shiny new tool.
Electric Vehicle Startup Nikola Motors is using Crystal to power their software in production. You can read their story here.
The libraries available for Crystal are also somewhat limited. The available libraries for Crystal are not as diverse compared to Ruby’s Gems or Node’s npm packages.
Finally, if you are trying to build a niche product and solve a very specific problem, you might not be able to find documentation. For instance, I was trying to spin off a GraphQL server with Crystal. While there are some good examples in Github, I was unable to find any proper documentation or tutorials on this topic.
Crystal brings all the good parts of Ruby and none of its limitations. It is easy to migrate from Ruby to Crystal and vice versa. Crystal is fast, has a beautiful Ruby-like syntax, static types, and powerful features like macros for meta-programming. However, like every technology, Crystal has its own limitations.
The main limitation of Crystal is that it is not as mature as Ruby, Node, or Python. With a growing community of passionate developers backing Crystal, it might not take long for it to be the next big player in web development. As a Rubyist myself, I know I am keeping a close eye on Crystal’s development.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]