---
title: Crystal 0.16.0 released!
version: 0.16.0
summary: Types
thumbnail: +
author: asterite
---

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

This is a huge release that includes a major breaking change that was
[announced](http://crystal-lang.org/2015/12/24/the-future-of-crystal.html) a few
months ago: types of global, class and instance variables need to be a bit more explicit.

This release also includes other minor breaking changes and a lot of new goodies.

## The new global type inference algorithm

The new rules are explained in the [official docs](http://crystal-lang.org/docs/syntax_and_semantics/type_inference.html),
but let's quickly review the change.

Before this release, the type of global, class and instance variables was inferred
globally in the program by analyzing all uses. For example:

```ruby
class Some
  def initialize(@var)
  end
end

Some.new(1)
```

In the above snippet, `Some`'s `@var` was inferred to be an `Int32`. If you did this:

```ruby
Some.new(1)
Some.new("hello")
```

then it would have been inferred to be `Int32 | String` (a union type). And even
in the following code, `@var` was inferred to be an `Int32 | String`:

```ruby
class Some
  def initialize(@var)
  end

  def var=(value)
    @var = value
  end
end

some = Some.new(1)
some.var = "hello"
```

In this release, all of the above snippets won't compile anymore: the compiler now
needs to know the type of `@var` in a "obvious" way. For example, assuming the
intended type for `@var` is `Int32`, then we could write:

```ruby
class Some
  # Since only Int32 is accepted in the constructor, @var is inferred to be Int32
  def initialize(@var : Int32)
  end
end
```

Another common ways is using literals and constructors:

```ruby
class Some
  def initialize
    @int = 0            # Inferred to be Int32
    @string = "hello"   # Inferred to be String
    @bools = [] of Bool # Inferred to be Array(Bool)
    @time = Time.new    # Inferred to be Time
  end
end
```

The reason of this change is to allow, in the future, implementing incremental compilation
and improving overall compile times and memory usage. Right now there aren't many big projects
written in Crystal. Probably the biggest one is the compiler itself, and it takes 16 seconds
to compile it from scratch, and 1GB of memory. But bigger projects will exist, and even though
a programmer's computer should be fast and have a lot of memory, that's no reason to have her
wait, or waste CPU and memory. Yes, there are popular programming languages that can sometimes
reach huge compile times, but that's no excuse for us to do the same.

For the old global type inference to work, the whole code had to be held in memory,
as a big tangled web, because a change in the type of an instance variable could
impact any other method. With this change, methods can be analyzed locally.
And once they are, their type can be inferred and it can't change anymore.

Note that types in method arguments are not mandatory, **and will never be**.

The good side of this change is that since the types of instance variables must now be
obvious to the compiler, they will also be obvious for someone reading the code. The
programmer, too, has to stop analyzing the whole code to figure out what an instance
variable is supposed to be.

Our guess is that static type languages lovers will love this change, while more dynamic
type languages lovers will probably hate it, some a bit, others with fury.

The good news is that even after this change explicit types are still not that many.
As an example, these are some diffs that were needed in some projects to upgrade to the
new version:

* \- [crystal-toml](https://github.com/manastech/crystal-toml/commit/01119bedf59f6499b7fd848a1190c9e35840a319): 2 types annotations
* \- [webmock](https://github.com/manastech/webmock.cr/commit/46fa261a6c0ad05dc0e3d5adbab46224c056f1d6): 3 type annotations
* \- [crystal_slack](https://github.com/manastech/crystal_slack/commit/f3662ea24b06024c98f278525ab4c07ab55d32ec): 9 type annotations
* \- [crystal_brium](https://github.com/manastech/crystal_brium/commit/0f1e5a52f57a214584aa2ee4619c6bf3795bcda0): 3 type annotations
* \- [crystal-sqlite3](https://github.com/manastech/crystal-sqlite3/commit/b1c6c32ae563d5f4ae9cc1979883a91a18aa5bc4): 3 type annotations
* \- [crystal_lib](https://github.com/crystal-lang/crystal_lib/commit/f5839e93bcfd4672a37c250163f70d94a2d5efa1): 55 type annotations
* \- [shards](https://github.com/crystal-lang/shards/commit/333bdcaecc1826f9e8df85dc9b0433005e7ad84a): 32 type annotations
* \- [radix](https://github.com/luislavena/radix/commit/9003075ec7cdd485eb793eb741f9ba2794c697b6): 3 type annotations, plus making some types generic
* \- [minitest](https://github.com/ysbaddaden/minitest.cr/commit/60215ad0e1a88b1625f1d90fec4048deb1ad7847): 13 type annotations
* \- [artanis](https://github.com/ysbaddaden/artanis/commit/27817680a9d1a2bc6072855f860b277f393919a1): 1 type annotation
* \- [msgpack](https://github.com/benoist/msgpack-crystal/commit/51d379a9f3057b5583470c8916da6853348b4288): 5 type annotations

<br/>
In general, few type annotations were needed. That sometimes depends on the programmer's style: he might
feel more comfortable with more explicit types, so this change affects him less. In other cases more
annotations are needed, but understand that these projects have been around for a long time now, and
adding 30 type annotations at once instead of writing them when declaring a class is definitely more annoying.

Another reason for why not many type annotations were needed is that many were already there,
since the language was born:

```ruby
class House
  def initialize
    @rooms = [] of Room # This is a type annotation
  end
end
```

Empty arrays and hashes always needed their type specified, and these are very common
when initializing an object.

As can be seen above, many important Crystal shards have already been updated and will work
with this release.

If you haven't upgraded yet, the recommended approach is to ask the old compiler (0.15.0) these types,
by doing `crystal tool hierarchy your_program.cr` and then adding the necessary type annotations that
the new compiler (0.16.0) will ask. To have both versions side by side you can use the excellent
[crenv](https://github.com/pine/crenv) by [pine](https://github.com/pine).

## The goodies

Putting the big breaking change aside, this release includes many goodies.

### FreeBSD and musl libc support

Thanks to [ysbaddaden](https://github.com/ysbaddaden) (you might know him from
[shards](https://github.com/crystal-lang/shards)) FreeBSD and
[musl libc](https://www.musl-libc.org/) support is included in this release.

His [contribution](https://github.com/crystal-lang/crystal/pull/2442) will also make
it easier to port Crystal to other platforms (but, before you ask it in the comments
section, no, there's still no Windows support, and this change probably doesn't help
much in that regard.)

**EDIT:** a FreeBSD package is now in the [releases](https://github.com/crystal-lang/crystal/releases/tag/0.16.0) page.

### Named arguments everywhere

Before this release, named arguments could only target arguments that had a default value:

```ruby
def method(x, y = 1)
  x + y
end

method 10           # OK
method 10, y: 20    # OK
method x: 10        # Error
method y: 20, x: 10 # Error
```

Now, all of the above compile. This can be specially useful for methods that have
a long list of arguments. For example, which one is more readable:

```ruby
require "oauth2"

# Option 1
client = OAuth2::Client.new(
  "some_host",
  "some_client_secret",
  "some_client_id"
)

# Option 2
client = OAuth2::Client.new(
  host: "some_host",
  client_secret: "some_client_secret",
  client_id: "some_client_id"
)
```

Regardless of which option you find more readable, the first one is actually wrong:
the method arguments are `(host, client_id, client_secret)`, and they are
being passed in a wrong order. But, because all of them are strings, the compiler
doesn't complain. The second option is more robust because we don't need to
remember the correct order and we use descriptive names.

### More big numbers

[BigFloat](http://crystal-lang.org/api/BigFloat.html) (thanks to ~~[Exilor](https://github.com/Exilor)~~)
and [BigRational](http://crystal-lang.org/api/BigRational.html) (thanks to [will](https://github.com/will))
were added to the standard library, and together with [BigInt](http://crystal-lang.org/api/BigInt.html)
should be enough for math programs and other use cases.

### Binary search

Binary search methods were added in `Array` and `Range` (thanks to [MakeNowJust](https://github.com/MakeNowJust)).

For example, let's solve x<sup>3</sup> + x<sup>2</sup> + x - 2:

```ruby
answer = (-Float64::INFINITY..Float64::INFINITY).bsearch { |x| x ** 3 + x ** 2 + x - 2 >= 0 }
puts answer # => 0.810536
```

### JSON and YAML improvements

Enums, `BigInt` and `BigFloat` can now be mapped to JSON and YAML very easily. For example:

```ruby
require "json"
require "big"
require "big/json"

enum Color
  Red   = 1
  Green = 2
  Blue  = 3
end

class Lollipop
  JSON.mapping({
    color:    Color,
    diameter: BigFloat,
  })
end

json = %({"color": 2, "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
p lollipop # => #<Lollipop:0x10c962f30 @color=Green, @diameter=12.3456789123456789>

json = %({"color": "Blue", "diameter": 12.3456789123456789})
lollipop = Lollipop.from_json(json)
p lollipop # => #<Lollipop:0x1033a4f00 @color=Blue, @diameter=12.3456789123456789>
```

### Other goodies

Make sure to read the [changelog](https://github.com/crystal-lang/crystal/releases/tag/0.16.0) for other minor goodies (and a few minor breaking changes as well.)

> **THANKS:**
> We'd like to thank everyone that made this release possible, by testing the new changes and reporting bugs,
> upgrading code to the latest version, sending pull requests, commenting suggested features, adding docs
> and more.
