Learning Crystal 01: the basics
03 March 2019
DISCLAIMER: HIC SUNT DRACONES! These are my “study notes”. They’re not 100% guaranteed to be correct, though I’m writing them to be as factual as possible.
A couple of weeks ago I decided to invest some time on Crystal, a programming language that strives to be fast as C and “slick” (read “simple”, “elegant”, “beautiful”) as Ruby. Here’s some of my initial notes and observations.
Installation & CLI
To download the compiler and related programs (such as
shards, the dependency
manager), just go to the installation page
on the website. There’s packages for all major GNU/Linux distributions.
The Crystal compiler CLI is quite simple:
Command: init generate a new project build build an executable docs generate documentation env print Crystal environment information eval eval code from args or standard input play starts Crystal playground server run (default) build and run program spec build and run specs (in spec directory) tool run a tool help, --help, -h show this help version, --version, -v show version
The CLI can create a boilerplate of a Crystal project with the
$ crystal init
It even initialize the project directory as a git directory with a simple README page and a LICENSE notice (by default, the MIT license; I’m not sure if there’s a way to choose what license should be used).
Following the opinionated nature of Golang, Crystal offers some built-in ways of doing documentation and testing. You can see some “uniformity” in many Crystal projects out there, which is something that I personally value.
The Crystal equivalent of Ruby’s Gems are Shards. A shard could be a tiny
library or a whole framework. Shards could be initialized with the
$ shards init
To control the dependencies, Shards makes use of a manifest file called
shard.yml. The dependencies (and their versions) are locked on the lock file
install command does not allows you to specify what
shard to install. It simply read the manifest file and installs it into a local
lib directory. You can’t do
shards install my-shard; you have to manually
edit the manifest and include it yourself.
Counter-intuitive, but okay.
The code is very similar to Ruby. A “Hello World” program can be written in one line:
puts "Hello World"
To import, the
require keyword is used.
# main.cr require "colorize" require "./module"
At the first line we’re requiring a module from the standard library called
colorize. The colorize module can change the foreground and background color
of the text inside the terminal, as well the style (bold, dim etc).
At the second line we’re requiring a local file. When requiring local files,
the path must be relative to the main file. The example below illustrates the case
when a file (
main.cr) requires another file within the same directory
├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── shard.lock ├── shard.yml └── src ├── module.cr └── main.cr
Supposing a structure of nested directories:
└── src ├── main.cr └── module └── file.cr
file.cr would have to be required as:
# main.cr require "./module/file.cr"
Crystal is based on the LLVM. When passing the
flag to the compiler, you can see the C compiler in action. The build time varies
a lot. The “Hello World” example compiles in half of a second, on average.
Bigger projects consumes up to thirty seconds.
The “Hello World” binary size is about 1.1 MB. The binary doesn’t grow as much as Golang binaries when adding libraries and other resources. However, Crystal binaries are system-dependent: missing headers or libraries can break the program.