Doing Crystal #1: A Ruby Comparison
Tags: crystal, tutorial, ruby, series
Published: 2019-05-22 04:17:26

Hello world, and welcome to this series of blog posts which I'm titling "Doing Crystal". Yes it is a meth joke, and yes you'd better have a sense of humor if you're going to be a part of this series. You've been warned.

In this series of blog posts I will walk you through the beautiful world of Crystal, or as I like to call it, Ruby's over achieving younger sibling. If you haven't ever had a run in with Crystal then you're in for a treat, so sit down, buckle up, and enjoy the ride, Buttercup.

So what is Crystal? Crystal is a statically typed, compiled, garbage collected language with a syntax that is hauntingly familiar to anyone that has ever touched Ruby. It uses LLVM to compile your beautiful Ruby-esque code down to machine code, and in benchmarks is consistently much closer in speed to C++ than Ruby. Crystal development started in 2014, so it is about 20 years younger than Ruby and still in pre-release status at the writing of this article, but that doesn't mean you shouldn't pay attention to it. On the contrary I think that Crystal has amazing potential.

But if it's so much faster than Ruby, is a comparison really fair? Sure it is! I want to show you how you can take code that looks like Ruby and make it type-safe and make it 44x faster (based on the [](https://github.com/kostya/benchmarks)). The Ruby ecosystem is still much more developed with 152,000 available Ruby gems as opposed to just over 4,000 Crystal shards, but such is to be expected from languages that are 20 years apart.

So, without further ado, let's get down to business and compare these two amazing languages.

## Crystal vs Ruby

First let's start with what a lot of people, me included, consider the most important piece of any programming language. The syntax. Sure speed is nice and everything, but if your fast code ends up looking like a steaming pile of cow dung (I'm looking at you C++) then the maintainability factor for your project goes way down.

Let's start with an example from the [Crystal lang website](https://crystal-lang.org), a super simple HTTP server.

First the Ruby sample:

![Ruby HTTP Server](https://i.ibb.co/dGpXbgR/http-server-rb.png)

Creating a HTTP server in Ruby is interesting. It's not at all intuitive and makes life kind of difficult. Yes, in Ruby you can also just use Sinatra or any other gem to create a server, but this example is about doing it in pure Ruby.

Now for Crystal:

![Crystal HTTP Server](https://i.ibb.co/P4dvFW0/http-server-cr.png)

Wait, that's it? How simple is that. You import from http/server instead of socket, you use a block to handle the looping and the block hands you a context. There's no blocking loop, no need to manually define headers, and no real complexity.

Ok so some API's are simplified, but what about this static typing? Let's take look at another couple examples.

First the Ruby code:

![Runtime Error](https://i.ibb.co/t3tCmcq/runtime-error-rb.png)

Now sure, any good Ruby dev would do a type check in the sum method to make sure that only integers are accepted, but that's extra work and even the best devs can miss things.

How about some Crystal:

![Compile Error](https://i.ibb.co/SyhXCdk/compile-error-cr.png)

This still throws an error, but the difference is when. A compile error is much better than a runtime error, because runtime errors are usually caught by the end-user. The error thrown is:

```shell
no overload matches 'Int32#+' with type (Int32 | String)
Overloads are:
 - Int32#+(other : Int8)
 - Int32#+(other : Int16)
 - Int32#+(other : Int32)
 - Int32#+(other : Int64)
 - Int32#+(other : Int128)
 - Int32#+(other : UInt8)
 - Int32#+(other : UInt16)
 - Int32#+(other : UInt32)
 - Int32#+(other : UInt64)
 - Int32#+(other : UInt128)
 - Int32#+(other : Float32)
 - Int32#+(other : Float64)
 - Number#+()
Couldn't find overloads for these types:
 - Int32#+(String)
arr.reduce(0) { |acc,i| acc + i }
                              ^
```

As you can see, not only does it throw an error, but it tells you exactly what the problem is. In this case the problem is that you can't add an integer to a string, even a string that has an integer in it.

And now you see some of Crystal's extremely powerful type system. All things in Crystal are typed, from Arrays to Hashes to variables. Because of this type safety the compiler absolutely will not allow you to make mistakes where types are concerned, and that means that runtime errors are basically nonexistent.

Now I'm not saying that you can't make mistakes in Crystal. You can still do stupid things like creating an infinite loop, and stack overflows aren't nonexistent. Crystal is still pre-release software after all. But the amount of safety you get from Crystal as opposed to Ruby is astounding.

That's it for this edition of Doing Crystal. Please remember to like, share, and subscribe, because yes, this is secretly a YouTube video and your life is a lie.

View the next post in this series [here](https://dev.to/watzon/doing-crystal-2-getting-started-with-crystal-13dk).

Some helpful links:
https://crystal-lang.org/
https://github.com/kostya/benchmarks
https://github.com/kostya/crystal-benchmarks-game
https://github.com/crystal-lang/crystal
Find me online:
https://medium.com/@watzon
https://twitter.com/chrystal_coder
https://github.com/watzon
https://watzon.me