Crystal is a very interesting language and has become one of my favorites to work with. It’s constantly compared to Ruby and is often marketed as an alternative to write performant code but with a nice syntax.

It’s a good marketing strategy and, in my opinion, the language lives up to the hype. When I’m writing Crystal I feel a lot of the similarities to Ruby, to a point where it even affects me when I go back to Ruby.

Of course, there are differences between both languages and that’s what I’m focusing on in this 2 part post. In part 1, I focused on the differences in Crystal that annoyed me and that which I believe to be things that any newcomer might also find frustrating or get tripped by, because of how much they contrast with Ruby.

This post focuses more on the things I like about Crystal. The things I think make it awesome to work with and that I miss when working with Ruby. In fact, in one specific case, it’s something that seems so rubyesque I keep trying to use it in Ruby and causing syntax errors in my scripts and apps.

Thing #1: It forces you to deal with nils

To start things off, I’m going to talk about one of the things I mentioned as annoying in Crystal. The type system forces you to deal with nils. The reason I put it in both lists is simple - I have a love/hate relationship with this feature.

Sometimes it’s pretty great as it warns you of some nils you may not be aware of, especially around constructors. If not all constructors of a class set an attribute that is not nilable it won’t compile.

The nil checks are also pretty useful when mapping out JSON objects from API responses, as I feel that’s where I usually get the most undefined/nil errors. If you define the type of an API response properly, setting the correct attributes as nilable , you can rest assured the compiler will help you avoid those pesky undefined/nil errors in whatever code you write using that API response.

However, as I pointed out in my previous post, writing code so that the compiler doesn’t complain about nils without being verbose takes some getting used to.

Thing #2: JSON parsing/serialization is awesome

There’s more than one way of parsing JSON in Crystal. The preferred way is to use the JSON.mapping macro like so:

This basically defines how your class or struct is represented in JSON. The macro call allows for some configuration options that make it very versatile when describing an API’s JSON response. Just the basic form of the macro, used by calling mapping(key_name: Type) , gives you the following for free:

Getters and setters for those properties in that class defined. A way of creating an instance of that class or struct from a JSON string by running A.from_json . A way to serialize an instance of that class into a JSON string by running instance.to_json . A new type you can use in a JSON mapping of another class.

That last one gives you a neat way of splitting complex JSON structures into separate models.

The more complex form of the mapping macro like mapping(key_name: {type: Type, nilable: true, key:"keyName"} has a bunch of options you can define per key.

You can define a different key name for the attribute so you don’t give up your beautiful snake case name conventions because of some stupid API that decided to name everything camelCased.

The macro also lets you mark certain attributes as nilable, which then lets you use the compiler to your advantage and forces you to deal with the nils in places you might forget. (Note: in case you just want to define a key as nilable you can just use the ? type like so mapping(key_name: Type?) ).

Mixing all of these features together can be used to represent complex API responses:

Thing #3: Has method overloading

This is something you would have never seen or used if you have only ever worked in Ruby/Python/Javascript land. Usually, when you have a statically typed language you have method overloading. This lets you define a method multiple times but with different type signatures for the methods.

For example, have you ever written code in Ruby that looks like this?

Well with method overloading in Crystal you can write it like this.

And thanks to the union types in Crystal the method overloading is pretty robust.

Thing #4: The to_proc syntax is way cooler

In Ruby there’s a neat shorthand you can use when calling methods that require code blocks like map or select . Whenever you have something like collection.map{|e| e.name } you can write it as collection.map(&:name) .

This is a pretty neat shorthand but it never made much sense to me that the syntax used a colon : . In my mind I always saw the ampersand & as a placeholder for the code block argument and the colon : as the dot . of a simple method call.

In Crystal, that’s basically how it’s done collection.map(&.name) . This is a syntax that makes much more sense to me, to the point where I’m constantly writing Ruby code like that. This divergence in syntax from Ruby doesn’t stop at the dot, you can also chain method calls on the ampersand and you can pass in arguments, the following is all valid crystal code:

Thing #5: Case statements are awesome

This is something I wasn’t expecting because I always hated case statements. I think it’s trauma from my C days in college and having to write break everywhere and always trying to be clever and have cases where it was useful to have it run two expressions sequentially.

It was a nightmare, but thanks to a type system and cool to_procs case statements in Crystal are pretty awesome. Here are a couple of things you can do with them.

You can match on type:

Of course, you can use union types there.

You can call methods on them:

And you can match regexes, which is something Ruby also does:

About the samples

If you have been paying attention to the examples you might get the feeling they’re coming from the same codebase, that’s because they are.

To try and illustrate the point of this post I created a simple Crystal app that queries the Marvel Comics API.

You can find the code here, also you’ll need the API keys for it to work.

And that’s the end of Part 2, I hope I have done a good job encouraging you to look into Crystal as it has some pretty neat features. If you’re thinking of playing around a bit with Crystal here are a few suggestions:

Fork the repo to play around with the Marvel API

Create a simple command line app to automate something in your day to day.

Look into open source projects that do things you’re familiar with or would like to know how it works, like:

Crecto a database wrapper

crystal-pg a postgres driver

Scry a language server implementation

Lucky or Amber which are rails like frameworks

Kemal which is a Sinatra like framework

SushiChain a blockchain implementation

You can also just browse the github Crystal project or create something new with it.