authors/bcardiff.jpg Brian J. Cardiff 05 Jun 2019

Crystal 0.29.0 released!

Crystal 0.29.0 has been released!

This release comes with many fixes in the compiler and some polishing in the std-lib. There is some work-in-progress related to multi-threading in other branches and whiteboards still.

There were 116 commits since 0.28.0 by 24 contributors.

Let’s review some of the most relevant changes in this release. But don’t miss the rest of the release changelog which has a lot of valuable information.


In #7758 a bug in the require file path algorithm was fixed. If your shard of application stops compiling it’s maybe due to an extra pair of ../ or a requirement missing. Keep calm and fix the paths.

Since #7582 the compiler is a bit pickier (as it always should’ve been) with respect name of variables. Shouting and asking is no longer allowed, so ! and ? are disallowed at the end of variables. They are allowed only in methods name (and in the special $?).

Deprecation warnings were introduced in 0.28.0, and there were a couple of undetected cases. Since #7724 the analysis covers initialize methods and methods with named args. Remember to build and spec with --warnings=all --error-on-warnings options since this feature is opt-in for now.

Effective error reporting depends heavily on tracking back an AST node to the original location. More cases are now handled since #7827.

During the last couple of releases, we’ve been introducing a couple of feature toggles to introduce new semantics. We were missing a way to run the existing compiler specs against these toggles when they affect low-level phases of the compiler. Maybe #7837 will only be relevant to the ones that want to dig into the compiler itself.

Language semantics

Since #7818 the compiler is a bit more strict regarding how new/initialize methods are defined when they’ve been included from a module. All in all it aims for consistency with initialize methods defined in a hierarchy of types.

In #7801 the behaviour of sizeof and instance_sizeof is improved for abstract structs and modules. In some cases it used to compile when it shouldn’t, and there could be some wrong sizes returned.

When declaring an enum flag type its members are Int32 by default, and you are allowed to change the base type to other numeric types like Int8, UInt16, etc. Since #7776 64-bits numeric types can be used also without chances of blowing up if there were more than 32 members. #Internals


The crystal implementation tool got a really useful feature. Since #7742 the tool can be used to lookup class and module implementations. Although its usage depends on the editor, let’s see a command line example.

In a with the following content:

class Minion
  def initialize(@name : String)

m ="Stuart")

If the cursor is located at line 6 column 8, it will be in the middle of Minion of the We can ask the tool to locate all the places where the constant Minion is defined.

$ crystal tool implementations --cursor
1 implementation found

This search is semantic. If there is a Minion constant in another namespace it will not be shown as an implementation. And it works across all files included from the main file after the cursor location.

Standard library

The docs are filled with examples, from time to time there is a major update to keep them consistent. Check how an external tool built by the community was used one more time in #7718. #LovelyNewTraditions


There are a couple of refinements in the String API. In #7633, String#at is deprecated in favor of #char_at. A String is able to contain binary data so it’s better to have no doubts if you are intending to access a char or a byte. #UTF8FTW

In case your code parses octals using String#to_i, they will need to be prefixed with 0o and not only 0. So 0777 is 777 (dec) and 0o777 is 511 (dec). Read more at #0o17013. #0o0

String#camelcase got a new downcase option in #7717 and some String#to_i arguments were restricted to Bool in #7436.


Slice got sorting methods in #7597 and the #pointer was removed in #7581.


YAML mappings are now a bit more comfortable for String. If the mapping states that a String is expected, and if the YAML source provides a scalar, the value is interpreted as a string. No need to quote it in the YAML, or add #to_s methods on the code. Read more at #7809


This breaking change can probably be sent to /dev/null. In #7778 File::DEVNULL was renamed to File::NULL.


Extra! Extra! #7423 added multicast for UDP. Broadcast the news! Extra! Extra!

In case your code needed to handle big files via IO there was one stopper issue. IO#copy used to return a 32 bits number, since #7660 that is changed to a UInt64. We still encourage 32 bits by default, but some use cases demand a bit more, like… 32 more bits.


Names are hard, vol. 23425. In Crypto::Bcrypt::Password the #== method was deprecated in favor of #verify in #7790 to better reflect the semantic of the operation.

Next steps

Please update your Crystal and report any issues. We will keep moving forward and start the development focusing on 0.30.

Once again, check your code with --warnings=all. This will help in the migration of your codebase and will probably push some feedback about that tool. Many of the breaking changes in this release are actually deprecations, so you probably want to check for warnings in order to do a full upgrade to Crystal 0.29.0.

Don’t miss the rest of the release changelog which has a lot of valuable information.

The development is possible thanks to the community’s effort, 84codes’ support, and every supporter.