Dipping into Crystal

Mark Connell Engineering Director, Applications

DALL·E's interpretation of Christmas trees made entirely of black crystals

For this year’s Advent of Code, I decided to have a shot at completing excercises I attempt only using Crystal – a compiled, statically-typed language. Yet, inspired by Ruby.

On the surface, Crystal is indeed very much like Ruby. It’s syntax and many of the standard libraries mimic those found within Ruby. The baked in testing framework Spec, bares many resemblances to RSpec. Ruby has Gems, Crystal has Shards.

It’s even possible to write some code that can work in both langauges:

minions_meal_calories = {
  "Bob"   => [5324, 5176, 2197],
  "Kevin" => [2612, 15638]
}

minions_meal_calories.each do |minion_name, calories|
  total_calories = calories.sum
  puts "#{minion_name} ate #{total_calories} calories today!"
end

# Bob ate 12697 calories today!
# Kevin ate 18250 calories today!

The above is perhaps a bit simple, but will run in both a Ruby interpreter and the Crystal compiler. A notable difference however, is enumerating over an object in Ruby returns the object. In Crystal, after enumerating over the Hash, it returns Nil.

return_value = [1,2].each { |i| puts "#{i} number! ah ah ah!" }
puts return_value

# Ruby
# 1 number! ah ah ah!
# 2 number! ah ah ah!
# => [1, 2]

# Crystal
# 1 number! ah ah ah!
# 2 number! ah ah ah!
# => nil : Nil

As much as you’re unlikely to be assigning variables in this way.. It is a simple example of where we start to see divergence in the behaviours between the two languages.

When it comes to standard libaries, Crystal does away with some of the aliasing and syntactic sugars of Ruby:

calories = [850, 460, 1200]

# Ruby
calories.size
# => 3
calories.length
# => 3
calories.count
# => 3

# Crystal
calories.size
# => 3 : Int32
calories.length
# => Error: undefined method 'length' for Array(Int32)
calories.count
# => Error: wrong number of arguments for 'Array(Int32)#count' (given 0, expected 1)

In Crystal, only #size is a valid function for getting the size of the collection in question. And there is no #length function. #count in Crystal is a function to count the occurances of a given value within an Array.

Interestingly, in ruby #length is the method and #size is an alias. I found myself initially repeatedly attempting to type #length from habit of working with Ruby.

If you have Crystal installed, and want to further dip your toes.. crystal i from a terminal will boot an interactive console, similiar to an irb console. Alternatively, and my preference of the two options, is a playground web application that can be started by running crystal play.