Let's cook some Crystal!
Tags: perf, crystal, ruby, go
Published: 2017-12-15 19:15:58

---
title: "Let's cook some Crystal!"
canonical_url: https://marmelab.com/blog/2017/12/14/lets-cook-some-crystal.html
published: true
description: "In the jungle of new programming languages, Crystal is one of the most popular ones, but also the most mysterious. Let's take a look at it."
tags: perf,crystal,Ruby,golang
cover_image: https://marmelab.com/images/blog/20171025_crystal_language.png

---

Note: This post was originally posted on [marmelab.com](https://marmelab.com/blog/2017/12/14/lets-cook-some-crystal.html).

Crystal? Some of you may have heard about it in the best TV series of all the time, Breaking Bad! Thankfully, we're not gonna talk about drugs in this post, but about a fabulous programming language I've heard of recently.

![Breaking Bad Crystal Cooking](https://marmelab.com/images/blog/crystal_breakingbad.jpg)

In my constant quest to discover new languages and paradigms, I came across [Crystal](https://crystal-lang.org/). Crystal is a compiled, [statically typed](https://en.wikipedia.org/wiki/Type_system#Static_type_checking), and [object-oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) language. Its syntax is strongly inspired by Ruby, and its goals are mostly the same as [Golang](https://golang.org/).

As usual when I learn a new language, I started a fresh new project that I could publish on GitHub. My use case: [a CLI app](https://github.com/marmelab/laurel) intended to facilitate [Caesar Cipher](https://en.wikipedia.org/wiki/Caesar_cipher) operations.

During this post, I'll try to give a large overview of the language capabilities, together with code snippets.

## Ruby, Are You There?

As I said in the introduction, a lot of the Crystal syntax concepts were taken from [Ruby](https://www.ruby-lang.org/fr/). The main reason of this syntax choice comes from the language creators' background.

Ruby is an object-oriented, reflective and [dynamically typed](https://en.wikipedia.org/wiki/Type_system#Dynamic_type_checking_and_runtime_type_information) programming language. It was developed 20 years ago to provide productivity and fun to developers. It was used in many medium and large projects like *GitHub*, *Diaspora* or *Redmine* (my first happy Ruby experience), and made popular by RoR (*Ruby on Rails*). 

While Ruby is an interpreted and [multi-platform](https://en.wikipedia.org/wiki/Cross-platform) language (which runs on [YARV](https://en.wikipedia.org/wiki/YARV) VM), Crystal is not. That means Crystal needs to be compiled on the platform where it'll be executed.

As you are going to see later, Crystal is not Ruby, it *mimics* Ruby. If you're a Rubyist, you'll be a little disappointed by static typing and inference. Even so, many basic concepts have been taken from Ruby. Among them, we find *"Blocks"*, *"Symbols"* and *"Everything is an object" principle*.

### Crystal Blocks

[Blocks](https://crystal-lang.org/docs/syntax_and_semantics/blocks_and_procs.html) are heavily used in Crystal (as much as in Ruby). They allow to capture a block of code with its own context, and execute it later. It's almost the same thing as *closures* or *anonymous functions* in other languages.

Here is a part of code from my toy project.

```crystal
(1...Encoder::ALPHABET.size).each do |shift|
    decoded = Encoder.decode(encoded, shift)
    candidates << { key: decoded, count: ((decoded.split(' ') - [""]) & dictionary).size }
end
```

In this example, the block which is defined between `do |shift|` and `end` is called for each letter between `1` and `Encoder::ALPHABET.size` (thanks to [Crystal Range](https://crystal-lang.org/docs/syntax_and_semantics/literals/range.html)).

The last letter (defined by `Encoder::ALPHABET.size`) is excluded from the range because of `...`. To include the last letter, it would been necessary to use `..`, which is inclusive.

Within the `.each` call, the block is **"yielded"** with the corresponding function from [range.cr](https://github.com/crystal-lang/crystal/blob/v0.24.1/src/range.cr#L102). In fact, a block is called with the `yield` keyword from Crystal as described in the doc example below.

```crystal
def twice
  yield
  yield
end

twice do
  puts "Hello!"
end

# => prints "Hello!" twice
```

### Symbols

The **Symbol** is another interesting concept also found in Ruby. A Crystal [Symbol](https://crystal-lang.org/api/0.23.1/Symbol.html) is a constant which is identified by its name. Internally, Crystal holds a registry of Symbols, which are represented as an Int32.

```crystal

:hello === :hello # true
:hello === "hello" # false

```

Symbols are closely the same as [Elixir atoms](http://elixir-lang.github.io/getting-started/basic-types.html#atoms).

### Everything is an Object

In Crystal, as in Ruby, everything is an object. Effectively, since reading post, you've already experienced no less than 3 objects (Blocks, Symbols and Ranges). Just like in Ruby, all objects extend [Object](https://crystal-lang.org/api/0.20.1/Object.html). When you write Crystal code, most of the time, you write classes.

```crystal
module Curses
  class Window
  end
end

Curses::Window.new
```

However, Crystal can also be used in a functional way. As a module requires a class, the solution is to make the module ["self-extended"](https://crystal-lang.org/docs/syntax_and_semantics/modules.html#extend-self). For instance, I can write an `Encoder` module that *does not* contain a class by using `extend self`:

```crystal
module Encoder
  extend self

  ALPHABET = "abcdefghijklmnopqrstuvwxyz "

  def encode(uncoded : String, shift : (Int32 | Int64))
      dictionary = create_shift_dictionary(shift)
      normalized_uncoded = normalize(uncoded)

      normalized_uncoded.tr(dictionary.keys.join, dictionary.values.join)
  end

  [...]

end
```

Now I can call the `encode()` method directly, without a supporting class:

```crystal
include Encoder
encode('hello')
```

## Crystal Functionalities

Whereas Crystal picks some concepts from Ruby, it also comes with a lot of unexpected functionalities such as *Type inference*, *concurrency* and *compile time null reference checks*.

### Type Inference at its Core

*Type inference* is one of the most valuable Crystal functionnalities. It gives you the power to delegate the type attribution process to the compiler. Moreover, in association with [Union Types](https://crystal-lang.org/docs/syntax_and_semantics/union_types.html), it allows to give different types to the same variable.

```crystal
if 1 + 2 == 3
  a = 1
else
  a = "hello"
end

a # : Int32 | String
```

In the example above, the type of `a` is automaticaly infered from the [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (Abstract Syntax Tree) at compile time. It's also possible to assign the type manually, as shown below.

```crystal
a : (Int32 | String) = 1
```

Type Inference also works with [Arrays](https://crystal-lang.org/docs/syntax_and_semantics/literals/array.html), [Tuples](https://crystal-lang.org/docs/syntax_and_semantics/literals/tuple.html), [NamedTuples](https://crystal-lang.org/docs/syntax_and_semantics/literals/named_tuple.html), [Hashes](https://crystal-lang.org/docs/syntax_and_semantics/literals/hash.html)... 

```crystal
[1, "hello", 'x'] # Array(Int32 | String | Char)
{1, "hello", 'x'} # Tuple(Int32, String, Char)
{name: "Crystal", year: 2017} # NamedTuple(name: String, year: Int32)
{1 => 2, 'a' => 3} # Hash(Int32 | Char, Int32)
```

Syntaxic sugar and shortcuts exist to declare empty typed structures:

```crystal
[] of Int32 # same as Array(Int32).new
Tuple(Int32, String, Char) # Tuple(Int32, String, Char)
NamedTuple(x: Int32, y: String) # NamedTuple(x: Int32, y: String)
{} of Int32 => Int32 # same as Hash(Int32, Int32).new
```

### Concurrency with Channels and Fibers

In addition to its fun syntax and static typing system, Crystal brings some concurrency capabilities (inspired by [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes)) through [Fibers](https://crystal-lang.org/docs/guides/concurrency.html#fibers). It's one of the most valuable functionalities of Crystal in comparison to other compiled languages

[Concurrency](https://en.wikipedia.org/wiki/Concurrency_(computer_science)) consists of running several tasks in the same time interval through operation switching. This concept is often mistaken with [parallelism](https://en.wikipedia.org/wiki/Parallel_computing), which consists of running multiples operations simultaneously (mathematically, in parallel).

Crystal Fibers can be compared to Golang's [Goroutines](https://gobyexample.com/goroutines). The main difference lays in the way Crystal allocate operations to CPUs. When Golang uses all availables CPUs, Crystal is only capable of using one of them for the moment.

Fibers use the same `message passing` system as Golang to achieve synchronisation and data passing between Fibers. It uses a kind of light-weight pipes called [Channels](https://crystal-lang.org/docs/guides/concurrency.html#channels).

Here is a little example of asynchronous operations written with Goroutines and Fibers. It'll give you a more concrete example of Fibers usage.

```go
// GOLANG

messages := make(chan string)
defer close(messages)

go func() {
    time.Sleep(time.Second * 5)
    messages <- "ping"
}()

msg := <-messages // Program will wait for 5s
fmt.Println(msg) // => ping

```

```crystal
# CRYSTAL

messages = Channel(String).new

spawn do
  sleep 5.seconds
  messages.send("ping")
end

msg = messages.receive # Program will wait for 5s
puts msg # => ping

```

In this example, I used the `channel` system to provide an exchange pipe between the main thread and the routine (async thread).

To declare an async thread, the `spawn` keyword with an associated [code block](https://crystal-lang.org/docs/syntax_and_semantics/blocks_and_procs.html) is used on the Crystal side. With Golang, an anonymous function is started in a goroutine via the `go` keyword ahead of it.

At assignation time (in this example), the main thread is stopped until the corresponding `channel` sends data back.

### Null Reference Checks

In you career, you've certainly heard of "NullPointerException" or the [The Billion Dollar Mistake](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare). This well known concept comes from the fact that it's deadly simple to call on a reference which is `Null`.

In Crystal, this kind of exception can't happen. A checks is issued at compile time to prevent it, thanks to Static Typing.

```crystal
if rand(42) > 0
  hello = "hello world"
end

puts hello.upcase
```

The previous code will fail with a compile time exception.

```crystal
$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))

puts hello.upcase
          ^~~~~~
```

This exception occurs because `hello` can be either `String` or `Nil`, and there's no `upcase` method on `Nil`.

## Crystal Tooling

Another argument in favour of Crystal is its great standard library, which covers most of the usual needs. [A lot of tools](https://crystal-lang.org/api/0.23.1/) are bundled with Crystal itself (HTTP, JSON, Markdown Parser and so on), making it ready to use instantly. 

For example, here is a small HTTP server written in Crystal.

```crystal
require "http/server"

server = HTTP::Server.new(8080) do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world, got #{context.request.path}!"
end

puts "Listening on http://127.0.0.1:8080"
server.listen
```

## Crystal Ecosystem

Despite its youth, Crystal has gained a lot of popularity in no time thanks to its Ruby-like syntax. It actually shares hype in the declining rubyist's world with another language, [Elixir](https://elixir-lang.org/).

Most Crystal-based projects are very confidential for the moment. Nevertheless, some of them have gained popularity rapidly:

- [KEMAL](https://github.com/kemalcr/kemal) - Fast, Effective, Simple web framework (including websockets, etc)
- [CRECTO](https://github.com/Crecto/crecto) - Database wrapper (inspired by Elixir's Ecto)
- [SIDEKIQ](https://github.com/mperham/sidekiq.cr) - Simple, efficient job processing (Including web monitoring UI)

Crystal bundles with an easy-to-use dependency management system. It consists of a simple YAML file (named shard.yml) listing dependencies and associated versions. It looks like the following:

```yaml
name: MyAmbitiousProject
version: 0.1.0

dependencies:
  openssl:
    github: datanoise/openssl.cr
    branch: master

development_dependencies:
  minitest:
    git: https://github.com/ysbaddaden/minitest.cr.git
    version: ~> 0.3.1

license: MIT
```

This way, a simple `crystal deps` command is enough to retrieve needed dependencies into the project tree.

If you're curious to discover other interesting Crystal projects, a [dedicated portal](https://crystalshards.xyz/) has been created specially for that purpose.

## Conclusion

Crystal has been first released in 2014. It's a relatively young language for the moment, but it promises a bright future.

Its advanced type inference system combined with static typing and union types give Crystal the feeling of a higher-level scripting language, with performances close to the metal. It can be a good alternative to Golang for modest performance needs.

Moreover, if you're already familiar with Ruby, Crystal is the first choice language. It offers good performances without having to bear Golang's heavy syntax.

Finally, if you like this language but need [distributed operations](https://en.wikipedia.org/wiki/Distributed_computing), you can take a look at [the Elixir language](https://elixir-lang.org/getting-started/introduction.html), which is very appreciated by rubyists, too.

If you're interested in the project associated to this post, you should take a look at [the repository](https://github.com/marmelab/laurel). It'll also give you a good start to dockerize Crystal apps in the same time.