---
title: Crystal 0.36.0 released!
version: 0.36.0
summary: Crystal has a new development release.
thumbnail: +
author: bcardiff
comment_href: https://disqus.com/home/discussion/crystal-lang/crystal_0360_released/
---


[Crystal 0.36.0](https://github.com/crystal-lang/crystal/releases/tag/0.36.0) has been released!

Since 0.35.1 there has been lots and lots of polishing, new features, and important fixes. This created a bigger delta than we wanted to transition from the last 0.x release to the first 1.0-preX. As a result, we are releasing a 0.36.0. This should help the community migrate their packages with less friction to the changes that will appear in 1.0. It will also give us a chance to get rid of a couple of recently introduced deprecations.

Note that this release will be available in [the new apt and rpm repositories post](/2020/08/24/announcing-new-apt-and-rpm-repositories/), as well as GitHub release artifacts. You might need to update your package repositories.

There were [346 commits since 0.35.1](https://github.com/crystal-lang/crystal/compare/0.35.1...0.36.0) by 54 contributors.

Let’s get right into some highlights in this release. Don't miss out on the rest of the [release changelog](https://github.com/crystal-lang/crystal/releases/tag/0.36.0).


## Language changes

Although instance variables can have annotations, we must apply them in the base class that declares them. So we reject annotations on instance variables redefined in a child class. We might lift this restriction in the future, but we are going to play it safe first. Read more at [#9502](https://github.com/crystal-lang/crystal/pull/9502).

The `**` operator is right-associative from now on. This matches Ruby and a couple of other programming languages. So `2 ** 2 ** 3 == 2 ** (2 ** 3) == 256`. But note that the negation is done before the exponentiation because of how we parse negative number literals. So `-2 ** 2 == (-2) ** 2 == 4`, which is different to Ruby. Read more at [#9684](https://github.com/crystal-lang/crystal/pull/9684).

Some releases ago `TypeNode#annotation` was added. The former less powerful `TypeNode#has_attribute?` is deprecated now. Read more at [#9950](https://github.com/crystal-lang/crystal/pull/9950).

## Compiler

There are several fixes that, although formally lead to breaking-changes, are mostly edge cases that required some polishing.

- You can’t use keywords as block arguments names. [#9704](https://github.com/crystal-lang/crystal/pull/9704)
- The `a-b -c` expression is now correctly parsed as `(a - b) - c`. [#9652](https://github.com/crystal-lang/crystal/pull/9652), [#9884](https://github.com/crystal-lang/crystal/pull/9884).

When using abstract `def`s, the compiler will enforce a couple of additional rules that should improve the maintenance of the code base.

- Abstract `def` implementations must honor abstract declaration regarding type restrictions, splats, default values, and keyword arguments.
[#9585](https://github.com/crystal-lang/crystal/pull/9585), [#9634](https://github.com/crystal-lang/crystal/pull/9634), [#9633](https://github.com/crystal-lang/crystal/pull/9633).
- Abstract `def` implementations must honor return type abstract declaration. [#9810](https://github.com/crystal-lang/crystal/pull/9810)

A simple example of what this enforce would be:

```crystal
abstract class Foo
  abstract def m(x = 1)
end

class Bar < Foo
  def m(x) # Error: because Foo#m can be called with no argument.
                #           Declare it as def m(x = 1) to make the compiler happy.
  end
end
```

Regarding typing, we improved a couple of stories.

- The type variables unification is more correct regarding union types. ([#10267](https://github.com/crystal-lang/crystal/pull/10267), thanks @HertzDevil)
- Exhaustive case expressions types to non-nilable value if all the cases allow it. [#9659](https://github.com/crystal-lang/crystal/pull/9659)
- Auto-casting deals better when the type restriction is a union by using, if possible, the exact type of the literal argument. [#9610](https://github.com/crystal-lang/crystal/pull/9610)
- Typing rules involving closured variables got smarter. [#9986](https://github.com/crystal-lang/crystal/pull/9986)
- Typing rules involving type restrictions, unions and boolean operators are really smarter. [#10147](https://github.com/crystal-lang/crystal/pull/10147).

How smarter you would like to know. Here is a sneak peak of what is now possible but it wasn’t before.

```crystal
x = 1 || 1.0 || 'a' || "" # x : Int32 | Float64 | Char | String

# when-clauses of >= 3 types now work, including else-branches of the case statement
case x
when Int32, Float64, Char
  typeof(x) # => Int32 | Float64 | Char
else
  typeof(x) # => String
end

# negations of disjunctions now work
if !(x.is_a?(Int32) || x.is_a?(Float64))
  typeof(x) # => Char | String
else
  typeof(x) # => Int32 | Float64
end

# the de Morgan equivalent of the above also works now
if !x.is_a?(Int32) && !x.is_a?(Float64)
  typeof(x) # => Char | String
else
  typeof(x) # => Int32 | Float64
end
```

You can also declare `def`s overloads with different named tuple types. Really handy if you are into using tuples a lot. Read more at [#10245](https://github.com/crystal-lang/crystal/pull/10245).

A breaking-change that affects C bindings is introduced in [#10254](https://github.com/crystal-lang/crystal/pull/10254). Callbacks within `lib` should be declared now as `alias` instead of `type`. One less quirk in the compiler.


```diff
lib YourLib
---  type ACallback = Int32 -> Int32
+++ alias ACallback = Int32 -> Int32
end
```

A second breaking-change that affects C bindings is that a Crystal nil value is no longer translated to a null pointer value. Read more at [#9872](https://github.com/crystal-lang/crystal/pull/9872).
## Standard library

The following top-level deprecated definitions are dropped: `CRC32`, `Adler32`, `Flate`, `Gzip`, `Zip`, `Zlib`, `with_color`. You will need to migrate to the `Compress` and `Digest` namespace. Read more at [#9530](https://github.com/crystal-lang/crystal/pull/9530), [#9529](https://github.com/crystal-lang/crystal/pull/9529), and [#9531](https://github.com/crystal-lang/crystal/pull/9531).

The `SemanticVersion` obeys the standard (as it should). This causes some breaking-changes if you rely on invalid version names, but otherwise you are safe. Read more at [#9868](https://github.com/crystal-lang/crystal/pull/9868).

Unfortunately some breaking-changes are silent. There is no simple way to show a warning. Such a case is when the return type of a method is changed. This is what happens to `File.size` and `FileInfo#size` since they now return Int64 instead of UInt64. Read more at [#10015](https://github.com/crystal-lang/crystal/pull/10015).

### Numeric

If you use `Complex`, you will need to rewrite some operations like `Complex#exp`, `Complex#log`, etc. to `Math.exp`, `Math.log`. This is the same API as for other numerical types. Read more at [#9739](https://github.com/crystal-lang/crystal/pull/9739).

### Text

`String` can hold arbitrary byte sequences. When these turned out to be invalid UTF-8 sequences, operations like `String#index`, `String#includes?`, and `Char::Reader` were misbehaving. In the presence of an invalid UTF-8 sequence, the data is now iterated a bit more slowly, like 1 byte at a time, until a valid sequence is found. Read more at [#9713](https://github.com/crystal-lang/crystal/pull/9713).

### Collections

There is a set of changes seeking consistency over the collection types. Unfortunately some are silent breaking changes.

- `Hash#reject!`, `Hash#select!`, and `Hash#compact!` return `self` always, as `Array`. Bonus point: you can method chain. [#9904](https://github.com/crystal-lang/crystal/pull/9904).
- `Set#delete` returns `Bool` to indicate if the element was present. [#9590](https://github.com/crystal-lang/crystal/pull/9590).
- Use `Hash#reject!` instead of `Hash#delete_if`. [#9878](https://github.com/crystal-lang/crystal/pull/9878).
- Use `Enumerable#select` instead of `Enumerable#grep`. [#9711](https://github.com/crystal-lang/crystal/pull/9711).
- `Hash#key_index` was removed. [#10016](https://github.com/crystal-lang/crystal/pull/10016)

But not every change is a removal, the following additions are also part of the release!

- Allow `Iterator#zip` to take multiple `Iterator` arguments. [#9944](https://github.com/crystal-lang/crystal/pull/9944)
- `Array#shift` and `Array#unshift` got faster. [#10081](https://github.com/crystal-lang/crystal/pull/10081)

### Serialization

We try to have one way to do things. This comes at the expense of needing to migrate old solutions that served us well. `JSON.mapping` and `YAML.mapping` are no longer part of the std-lib since there is a more flexible alternative: `JSON::Serializable`, `YAML::Serializable`. You can either migrate or, if you still want them, you can use [github:crystal-lang/json_mapping.cr](https://github.com/crystal-lang/json_mapping.cr) and [github:crystal-lang/yaml_mapping.cr](https://github.com/crystal-lang/yaml_mapping.cr). Read more at [#9527](https://github.com/crystal-lang/crystal/pull/9527) and [#9526](https://github.com/crystal-lang/crystal/pull/9526).

You can now declare properties that will be used only on serialization or deserialization. If your model has a field that should be hashed for serialization this comes in really handy. Read more at [#9567](https://github.com/crystal-lang/crystal/pull/9567).

Another addition is that you can use `use_json_discriminator` and `use_yaml_discriminator` with other types than `String`. For example, you can use numbers or enums to map the corresponding type. Read more at [#9222](https://github.com/crystal-lang/crystal/pull/9222) and [#10149](https://github.com/crystal-lang/crystal/pull/10149).

### Time

It’s time to mention some small breaking-changes:

- `Time::Span.new` deprecated variants are no longer available. ([#10051](https://github.com/crystal-lang/crystal/pull/10051)
- `Time::Span#duration` is deprecated in favor of `#abs`. `Time::Span` is already a duration, right? [#10144](https://github.com/crystal-lang/crystal/pull/10144)

### Files

Some breaking-changes are almost bug-fixes, but since they mean changing a known behavior, it is worth mentioning them as such. After [#10180](https://github.com/crystal-lang/crystal/pull/10180), `FileUtils.cp_r` will behave as expected when destination is a directory: the destination is calculated with `File.join(dest_path, File.basename(src_path))`.

### Networking

The `HTTP::Params` is renamed to `URI::Params`. In this release there is a deprecated alias that will allow you to deal with this migration more gradually. But I would not count on this alias to remain for long. Read more at [#10098](https://github.com/crystal-lang/crystal/pull/10098).

Another breaking-change is the renaming of `URI#full_path` to `URI#request_target`. Some edge-case behaviors also change to match the expected definition. Read more at [#10099](https://github.com/crystal-lang/crystal/pull/10099).

`URI::Params` (former `HTTP::Params`), as you know, is used to represent query strings that can hold multiple values for a key. When assigning a new value to a key you will override all values of that key. Read more at [#9605](https://github.com/crystal-lang/crystal/pull/9605)

```crystal
params = URI::Params.parse("color=red&color=blue&console=gameboy")
params["color"] = "green"
params # => => "color=green&console=gameboy"
```

The `HTTP::Client` can now be used with any `IO` instead of `TCPSocket`. If you happen to have an application that uses HTTP as protocol over UNIX Sockets, like Docker, you can now talk to it. Read more at [#9543](https://github.com/crystal-lang/crystal/pull/9543)

```crystal
require "http"

io = UNIXSocket.new("/var/run/docker.sock")
client = HTTP::Client.new(io, "localhost")
response = client.get "/v1.40/images/json"
```

### Logging

To have only one module to log them all, the former `Logger` is no longer in the std-lib. Migrate to `Log` or, for just a little longer, you can keep using [github:crystal-lang/logger.cr](https://github.com/crystal-lang/logger.cr). Read more at [#9525](https://github.com/crystal-lang/crystal/pull/9525).

If you need more excuses to migrate to `Log`, the `Log::Backend` can now emit their entries with different strategies that should help keeping the throughput of the app in the presence of logging. Read more at [#9432](https://github.com/crystal-lang/crystal/pull/9432).

### Crypto

Time for some security alerts. The std-lib prevents by default the Secure Client-Initiated Renegotiation vulnerability attack. In [#9815](https://github.com/crystal-lang/crystal/pull/9815) you can find more info and a small patch if you need to secure existing apps. Also, if you use `verify_mode=force-peer`, it is now correctly set up. Read more at [#9668](https://github.com/crystal-lang/crystal/pull/9668).

The `Digest` module is now backed by `OpenSSL`. Most used algorithms have their own class that is easy to use: `Digest::MD5`, `Digest::SHA1`, `Digest::SHA256`, `Digest::SHA512`. Bonus: `Digest#file` and `Digest#update(IO)` are available to compute digest from file and `IO` content. Read more at [#9864](https://github.com/crystal-lang/crystal/pull/9864).


### Concurrency

We hid some `Channel` API that should have been internal since the beginning. I doubt this will cause any issues. Read more [#9564](https://github.com/crystal-lang/crystal/pull/9564).

`Channel#close` now returns `true` unless the channel was already closed. This is handy in multi-thread, because you might need to know if the current fiber is the one that actually closed the channel. Read more at [#9443](https://github.com/crystal-lang/crystal/pull/9443).

### System

`Process.parse_arguments` will allow you to parse a `String` in the same way a POSIX shell does. This is internally used to improve `CRYSTAL_OPTS` parsing. Read more at [#9518](https://github.com/crystal-lang/crystal/pull/9518).

### Spec

The `#should` and `#should_not` methods can now take an additional argument for custom failure messages. Read more at [#10127](https://github.com/crystal-lang/crystal/pull/10127).

```crystal
describe "something" do
  it "something" do
    true.should eq(false), "Oh no!"
  end
end
```

## Others

The CI infrastructure for AArch64 hosted by [works on arm](https://www.worksonarm.com/) is making progress. We are still not releasing official packages. Read more at [#9508](https://github.com/crystal-lang/crystal/pull/9508).

The doc generator got many improvements. In case you weren't aware, besides generating HTML, it can also export the documentation information as JSON. This allows for the use of other documentation generation tools. With some of the recent additions listed in the changelog you can use [mkdocs via some community development](https://forum.crystal-lang.org/t/new-documentation-site-generator-mkdocstrings-crystal/2848).


## Next steps

Please update your Crystal and report any issues. We will keep moving forward and focusing on releasing 1.0.0-pre1 which should be a more stabilized version of 0.36 without many new additions.

> **THANKS:**
> We have been able to do all of this thanks to the continued support of [84codes](https://www.84codes.com/), [Nikola Motor Company](https://nikolamotor.com/) and every other [sponsor](/sponsors). It is extremely important for us to sustain the support through donations, so that we can maintain this development pace. [OpenCollective](https://opencollective.com/crystal-lang) is available for that.
>
> Reach out to [crystal@manas.tech](mailto:crystal@manas.tech) if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!
