6 minutes to read
5 Mar 2018
The Crystal Language
Intro
First things first, what is Crystal and why am I talking about
it at a ruby meetup?
Well it’s a programming language released in 2014 that claims to be as fast as
C and as slick as Ruby. Big claims right? I was pretty skeptical going in but
I’ve definitely found that it delivers good speed and some very nice looking
code.
Despite being so young it’s quite stable and has a strong standard library.
Examples
Before we dive too deep into it’s features lets just how similar is it to
Ruby. First up, Ruby:
unless ARGV.size == 1
puts "You must give me a max"
exit
end
max = ARGV[0].to_i
if max < 3
puts "You must specify a maximum 3 or higher"
exit
end
puts "Printing all primes up to #{max}."
previous_primes = [2]
puts 2
(3..max).each do |i|
next if previous_primes.any?{ |prev| i % prev == 0 }
previous_primes << i
puts i
end
Now lets compare that to the equivalent Crystal code:
unless ARGV.size == 1
puts "You must give me a max"
exit
end
max = ARGV[0].to_i
if max < 3
puts "You must specify a maximum 3 or higher"
exit
end
puts "Printing all primes up to #{max}."
previous_primes = [2]
puts 2
(3..max).each do |i|
next if previous_primes.any?{ |prev| i % prev == 0 }
previous_primes << i
puts i
end
Notice the difference? That’s right, there is none! This bit of code is both
valid Ruby and Crystal without any weird tricks or hacks.
Now lets look at a quick Kemal example. This is the Crystal
equivalent of Sinatra.
require "kemal"
get "/" do
"Hello World!"
end
Kemal.run
That’s it! You now have an incredibly fast and lightweight web server. The
benchmark on the Kemal site shows some very impressive metrics.
Benefits
Fast
It’s actually really quick! Lets have a quick look at the performance of my
very naive prime generator.
$ time ruby prime.cr 1000000
~~~~~~~~~~~~~~~
real 3m44.002s
user 3m29.560s
sys 0m3.927s
$ time ./prime 1000000
~~~~~~~~~~~~~~~
real 0m13.682s
user 0m13.121s
sys 0m0.339s
Clean
It’s inspired by Ruby, of course it’s beautiful.
Typed (but supports unions)
This helps catch errors at compile time and is one of the reasons it can be as
fast as it is.
$ crystal eval 'puts "Beep" + 42'
Error in line 1: no overload matches 'String#+' with type Int32
Overloads are:
- String#+(other : self)
- String#+(char : Char)
Let’s have a look at a slightly more complex example. Here we define a method
that can take in two different classes.
class User
def name
"Ms. User"
end
end
class Person
def name
"Mr. Person"
end
end
def example(contact : User | Person)
return contact.name
end
puts example(User.new) #=> Ms. User
puts example(Person.new) #=> Mr. Person
puts example("Hello")
#=> no overload matches 'example' with type String Overloads are:
# - example(contact : User | Person)
Macros
I’m not gonna lie, I haven’t had a reason to play with macros yet but they seem
incredibly powerful and possibly confusing. I believe the example below is
pretty self explanatory. Keep in mind this is turned into a function at compile
time, not during run time like Ruby, so it is a bit more limited.
macro define_method(name, content)
def {{name}}
{{content}}
end
end
# This generates:
#
# def foo
# 1
# end
define_method foo, 1
foo #=> 1
Good Standard Library
Out of the box you have a strong standard library with tools for Base64,
CSV, File, Gzip, HTTP, JSON, MarkDown, OAuth2, OpenSSL, URI, YAML, and Zip.
And many more! You can check the full list out at the API.
Shards
And when the standard library isn’t enough you’ve got shards! Which are the
equivalent of Ruby’s gems.
Unlike bundler that is a separate library and not maintained by the language
developers shards is built right in and completely supported. Everyone that has
Crystal has shards.
A simple shards.yml
looks like this:
name: Example
version: 0.1.0
authors:
- Sean Earle <sean.r.earle@gmail.com>
targets:
example:
main: src/example.cr
dependencies:
db:
github: crystal-lang/crystal-db
sqlite3:
github: crystal-lang/crystal-sqlite3
modest:
github: kostya/modest
crystal: 0.24.1
license: MIT
Cons
Sadly not everything is peachy in the land of Crystal, here’s a short list of
things where Ruby has it beat:
- No Windows support, this is promised in 1.0 and making good progress though
- No parallelism (but there is concurrency!), again, this is slated for 1.0
- Not a huge amount of libraries
- Small community
- Development has been kinda slow this past year
- Developer communication hasn't been amazing
While I don’t see Crystal disappearing I would be weary about building anything
particularly large or important in it just yet.
Gem Equivalents
If you’re still interested in trying Crystal out here is a list of gem/shard equivalents:
To find more just head over to CrystalShards and search. The
list of shards grows longer every day.
The End
I hope you’ve enjoyed my little introduction into Crystal!
If you are looking for a community, or even just some help, I’ve found
r/crystal_programming to be a
good resource.