I love Ruby. There…I said it. I am a Ruby fan. Ruby is expressive, powerful and elegant. It’s core mantra of “Achieving more with less” and it’s freedom and flexibility make it, in my opinion, one of the best languages out there. But there are a couple of downsides:

• Ruby is interpreted
• Ruby doesn’t force you to handle nil values
• Ruby doesn’t like C interop (you can do it…but it’s ugly as hell)

So recently, I discovered a language that really is “Fast as C, slick as Ruby”:

This post is a bit different from the others in my Summer Series. I don’t really have an end result I want to achieve here other than to get to know the language, so see this more as a showcase than a tutorial or something like that…

### What is Crystal? 🔮

Well…Crystal is a compiled, object-oriented, duck-typed programming language that aims to have the elegance of Ruby but with the speed of something like C. It first appeared in 2014 and, as of today, is still in pre-release stage which definitely makes it “new technology”. In this post, I’ll try to teach myself the core concepts of Crystal, write some Crystal code and try to really get to know the language.

So let’s start exploring!

### Installing the compiler

Unfortunately, Crystal doesn’t work natively on Windows yet. Therefore, we have to make use of WSL. I am using Ubuntu 18.04 as my WSL instance, where Crystal is supported out of the box.

curl -sSL https://dist.crystal-lang.org/apt/setup.sh | sudo bash
sudo apt install crystal


In addition to that, the language reference recommends installing some other tools. I won’t be installing all of them, instead I just picked 4 packages I think I’ll need at some point.

sudo apt install libssl-dev      # for using OpenSSL
sudo apt install libyaml-dev     # for using YAML
sudo apt install libgmp-dev      # for using Big numbers


### Hello world!

Let’s start with a simple “Hello world!”. In Crystal, you print with the puts statement. Which means that a “Hello world!” is as simple as:

puts "Hello world!"


Crystal also supports string interpolation, so we can do something like:

puts "Hello, world! The time is #{Time.now}!"


Now that we have that figured out, let’s move on to something more interesting.

### OOP

Classes in Crystal are declared like so:

class Animal
end


In Crystal, an object has a type and responds to some methods (the only way to interact with objects in Crystal). That means that for every property we want to have in our class, we need to declare a function to access these properties. The information of these properties is stored in instance variables, prefixed with @. Also, constructors are always a method with the name initialize.

class Animal
def initialize(name : String, age : Int8)
@name = name
@age = age
end
end


Technically, we could totally access these instance variables directly like so:

alex = Animal.new("Alex", 2)
puts alex.@name #=> Alex


But to my understanding this is to be avoided (although I couldn’t find out why). Therefore, we need to introduce getters.

class Animal
def initialize(name : String, age : Int8)
@name = name
@age = age
end

def name
@name #Return is implicit
end

def age
@age
end
end


So now we can call name.

alex = Animal.new("Alex", 2)
puts alex.name #=> Alex


The example above can be compressed by declaring the instance variables directly in the initialize parameters. Also, we can use macros from the Crystal standard library to make dealing with properties way easier.

class Animal
property age : Int8 #We can modify this
getter name : String #We can't modify this

def initialize(@name : String, @age : Int8)
end
end


Using this class could look like so:

alex = Animal.new("Alex", 2)
puts alex.name #=> Alex

puts alex.age #=> 2
alex.age = 10
puts alex.age #=> 10


We could also define methods for this class. When calling methods, one can omit the braces.

def to_json
"{\"name\": \"#{name}\",\"age\": #{age}}"
end

puts alex.to_json


### Inheritance

Next, let’s try some inheritance. To do so, I changed our Animal from a class to an abstract class and introduced an abstract method we’ll make use of.

abstract class Animal
property age : Int8
getter name : String

def initialize(@name : String, @age : Int8)
end

abstract def do_talk

def talk
"#{name} says '#{do_talk}'"
end
end


We can now inherit from this class like so:

class Dog < Animal
def do_talk
"Woof!"
end
end

class Cat < Animal
def do_talk
"Miau"
end
end


And use these classes like so:

john = Dog.new "John", 2
puts john.talk #=> John says 'Woof!'

mia = Cat.new "Mia", 4
puts mia.talk #=> Mia says 'Miau'


### Blocks

This language feature allows for some really nice code. Basically, you can pass on a block to a function. The cool thing is: those blocks are not lambdas! They’re actually being inserted into the function that you’re calling. Now…I don’t exactly know how this black magic works…but I do quite love it.

We don’t actually need to give the compiler any specifics about the block because it can figure out most things on its own.

def executeBlock
yield "the other side"
end

executeBlock do |x|
puts "Hello from #{x}"
end


It’s a bit complicated to wrap your head around this at first, but basically, this compiles to:

x = "the other side"
puts "Hello from #{x}"


The standard library does include a times method but let’s see if we can write our own…

def count(i)
c = 0
while c < i
yield c
c += 1
end
end

count 5 do |i|
puts "The current number is: #{i}"
end


And this would basically compile to:

c = 0
while c < 5
puts "The current number is: #{c}"
c += 1
end


### Union types

Crystal also supports something called a “union type”. This allows for a variable to have multiple datatypes at the same time. The cool thing about this is that you don’t even have to type out these union types. The compiler will pick these up for you (but that also means that the compiler will force you to deal with said types).

a = 10
b = "Hello"

c = rand < 0.5 ? a : b


Now, in every other (statically typed) language we obviously expect this to not even compile. But in Crystal, it does. Let’s append a typeof.

puts typeof(c) #=> (Int32 | String)


## なに!? 🤯

What kind of black magic is this?? Well…not so much black magic but a really smart compiler, actually…typeof returns a union type because the compiler figured out that rand < 0.5 ? a : b could’ve resulted in an Int32 or a String!

This is nice and all…but not really what the feature was meant for. This language feature is way more useful in a scenario like this:

def getDataOrNil
rand < 0.5 ? {firstname: "John", lastname: "Doe"} : nil
end

john = getDataOrNil
john_firstname, john_lastname = john[:firstname], john[:lastname]


Trying to compile this yields the following error message:

Which means that we have to deal with the possible null value like so:

if john != nil
john = john.as(NamedTuple(firstname: String, lastname: String))
john_firstname, john_lastname = john[:firstname], john[:lastname]

puts john_firstname
puts john_lastname
else
puts "No data found!"
end


### Simple HTTP server

Now that we have all of that (with all of that I mean blocks and union types), more or less, figured out, we can try building a simple HTTP server with Crystals built-in HTTP library. I tried to construct a simple HTTP server that just does a simple echo.

require "http/server"

server = HTTP::Server.new do |ctx|
ctx.response.content_type = "text/plain"
ctx.response.print(ctx.request.body != nil ? ctx.request.body.as(IO).gets : "Hello!")
#ctx.request.body can be nil so we have to manually handle this here
end

server.listen


### Concurrency model

So the concurrency model of Crystal is truly something else. At first, it might look a bit complicated but really it’s quite easy (easier than Rusts concurrency model anyways…) and incredibly powerful to the point where I don’t recall seeing something as powerful in any other modern language (except Rust and Go, of course). Unfortunately, Crystal does not yet have a model to manage parallelism (parallelism ≠ concurrency).

#### Note ⚠️

A concurrent system is one that can be in charge of many tasks, although not necessarily it is executing them at the same time. You can think of yourself being in the kitchen cooking: you chop an onion, put it to fry, and while it’s being fried you chop a tomato, but you are not doing all of those things at the same time: you distribute your time between those tasks. Parallelism would be to stir fry onions with one hand while with the other one you chop a tomato.

From the Crystal language reference

require "http/client"

spawn do
response = HTTP::Client.get "http://www.example.com"
response.body.lines.each do |line|
puts line
end
end

spawn do
5.times do
puts "Hello!"
end
end

sleep


Here we spawn two fibers (a fiber is a lightweight execution unit). The first issues an HTTP Get request, the second one prints “Hello!” five times. These fibers are put into an event queue. When the first fiber reaches HTTP::Client.get, it knows that it has to wait for a response. Therefore, the event queue proceeds to the second fiber and prints “Hello!” five times.

We could also spawn a call directly.

5.times do
spawn puts "Hi!"
end

sleep


Here, we create five fibers that will all just call puts "Hi!".

Of course, these fibers can also communicate with the main thread via a channel.

channel = Channel(String).new

spawn do
channel.send("Hello")
sleep 0.5 #Delay the channel from sending "World!"
channel.send("World!")
end