authors/beta-ziliani.jpg Beta Ziliani 3 weeks and 4 days ago

Crystal 1.2.0 is released!

We are delivering a new release with several bugfixes and improvements. Below we list the most important or interesting changes, without mentioning the several bugfixes. For details visit the release’s notes. Breaking changes are marked with ⚠️.


In this release we included 181 PRs since the 1.1.1 release by 32 contributors. We thank all the effort put into improving the language and its stdlib! ❤️

Platform support

As mentioned in the preparatory blog post for 1.2, we decided to lower the support for 32-bit x86 architecture. This is a direct consequence of focusing our efforts in more popular platforms: we do have some good news to share!

We are making progress in achieving full native Windows support, in this release including most notably a sockets implementation (#11205, #11137, #10605, #10605).

Related to Windows, and also relevant for ARM64 architectures, we fixed an important codegen bug. We are now in conditions to promote aarch64 platforms to Tier 1, expecting to include packages for them soon. This is also relevant for macOS with the M1 chipset: starting from this release we include a universal macOS package that works for x86 and M1 macs.

We discovered that two bugs appearing on Windows and M1’s macs are coming from LLVM 11 and 12. We expect the fix will come with the recently released LLVM 13. Crystal 1.2.0 is compatible with LLVM 12, although we advice against using LLVM 11 and 12.

Language changes

It is now possible to assign a subclass of a generic class to an element of the parent class:

class Foo(T); end

class Bar(T) < Foo(T); end

x = Foo
x = Bar

Also pertain to generic classes, there were situations in which the compiler was not properly substituting the generic argument (#11166, #11067.

The support for ThinLTO compilation was dropped, since it wasn’t working already since Crystal 0.25.


It is possible to add an underscore in for loops to ignore a value. For instance, in the following code the keys of the map are ignored:

{% for _, v, i in {1 => 2, 3 => 4, 5 => 6} %}
  p {{v + i}}
{% end %}

Additionally, there is a new file_exists? macro method to check the existence of a file (#10540), and #is_a? now recognizes the AST node hierarchy (#11062).


⚠️ We are continuing the trend started in the 1.1.0 version to help get better error messages and documentation: several methods were annotated with expected types. Adding typing annotations might break existing code in specific scenarios so, if this happens to you, please let us now.


The major improvement in the numeric area is the steps taken to support 128 bits integers (#11206 and #11245).

As minor improvements, it is now possible to adjust the precision in the output of Int#to_s; to iterate the set of representable floats through new methods #next_float and #prev_float; to use a negative exponential to a BigDecimal; and to calculate the integer square root of a number.


Mutable collections now include a Indexable::Mutable(T) module, which greatly expand the set of operations on certain collections such as BitArray and Deque. The following now works:

ba = # ba is BitArray[0000000000]
ba[0] = true          # ba is BitArray[1000000000]
ba.rotate!(-1)        # ba is BitArray[0100000000]

Additionally, Indexable::Mutable(T) was expanded to include stable and unstable sorting methods (#11254, #11029, #10163). The default sort operation now calls a stable algorithm.

⚠️ As a breaking change, Array#product was deprecated in favor of the new generic and better named Indexable#cartesian_product.

Another two contributions worth of mention: enumerables are equipped with method to tally them with a given predicate (Enumerable#tally_by); and the methods Array#transpose, Enumerable#reject, and Enumerable#to_h now work with tuples.


⚠️ The method IO#write_utf8 was deprecated in favor of the more descriptive name IO#write_string, because you can use it to write strings in all kinds of encodings, depending on the IO’s configuration. We also fixed a number of bugs related to using IO#write instead of IO#write_string to append text to an IO.


⚠️ In order to improve the security of the stdlib, URI.encode was deprecated in favor of URI.encode_path and URI.encode_path_segment whith safer semantics and names better fitting to the purpose.

There is now support for basic authentication taken from an URI in websockets (#10854), and proper handling of max-age and expires for cookies (#10564).


⚠️ String#unsafe_byte_at was deprecated since String has already a #to_unsafe method.

Crystal now supports Unicode 14.0.0.


There is a new method XML::Node#namespace_definition to obtain explicitly-defined XML namespaces of a node, and URIs can now be serialized to JSON and YAML.

Tools: new docs generator

The API docs now use markd to render Markdown (#11040). This puts an end to the shortcomings caused by the internal renderer implementation.


It is now possible to make install Crystal.

We have been able to do all of this thanks to the continued support of 84codes, Nikola Motor Company and every other sponsor. To maintain and increase the development pace, donations and sponsorships are essential. OpenCollective is available for that. Reach out to if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!