How to write Crystal Clear Code

Today, we’re going to explore an exciting programming language called Crystal — a compiled Ruby-syntax-like LLVM backend statically typed fully object-oriented language. The reason why I’m so excited about Crystal is the fact that it brings together the benefits of both compiled and dynamic languages.

Credit: Cristian Luchian

Brief history

Crystal was designed and developed by Ary Borenszweig and Juan Wajnerman in 2014. The purpose was to create a language that includes all the benefits of Ruby, but without its associated downsides. Namely, the language must be as elegant and productive as Ruby, but as fast and safe as a compiled/statically typed language.

Everything is an object

In Crystal, everything is an object. The definition of an object boils down to these points:

  • It has a type;
  • It can respond to some methods;

Data types in Crystal

Symbol is a number (Int32) but with a human-readable name — for example, :hello. Symbols can be used as identifiers or keys of any kind, such as as keys in a hash map.

Tuple is a fixed-size, immutable sequence of values. tuple = {26, "Arsen", '👨‍💻'} is an example of Tuple(Int32, String, Char). You can also assign labels to values, which will create a NamedTuple. For instance,tuple = { age: 26, name: "Arsen", avatar: '👨‍💻' } looks much better and allows us to reach values by using a symbol as a key tuple[:age] # gives 26.

Proc represents a pointer to a function and a context. The return type is inferred from the proc’s body. proc = ->(x : Int32) { x.to_s } # is a proc with one input argument and a return value of String type To invoke a proc, you invoke method.

A Proc can also be created from an existing method, like so:

Type system

Despite being a statically type-checked language, Crystal keeps the type system almost invisible for developers. Most of the time, it actually feels like you’re using a dynamically typed language instead.

Crystal achieves this by allowing a variable to have not only one type, but N-types at the same time.

In the example above, the variable a could be an Int or a String. In Crystal, this is known as a Union Type. The most interesting part is how methods are called on a union type. The rule is simple: all types in an union must respond to the method you’re trying to call.

It means that if you try to call a + 1, you will get a compile-time error because Strings do not respond to + methods.

If you want to call a type-specific method, a runtime check is required:


To define a method, you need to provide a name and specify a list of parameters. You can provide types for the parameters but this is completely optional.

The return value is the last computed expression within the method. In this case, the return type inferred based on the returning value.


Types in Crystal are non-nilable. To express nullability, Crystal uses a type called Nil, which means that if a method returns a value or nil, it will provide a union of some type and Nil.

Error handling

Lastly, Crystal deals with errors by raising and rescuing exceptions. To raise an exception you use raise "OH NO!" method and begin/rescue/end to catch exceptions.

This concludes my quick overview of the Crystal programming language, but if you want to learn more about it, please visit the official site.

Revolut launched in July 2015 with a punchy mission: to turn the financial banking sector on its head. With Revolut, users can set up an app-based current account in 60 seconds, spend abroad in over 120 currencies with no fees, hold and exchange 25 currencies in-app and send free domestic and international money transfers with the real exchange rate.