---
title: Crystal 0.25.0 released!
version: 0.25.0
summary: Crystal has a new development release.
thumbnail: +
author: bcardiff
---

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

As every release, it includes numerous bugfixes, cool features and performance improvements - in [400 commits since 0.24.2](https://github.com/crystal-lang/crystal/compare/0.24.2...0.25.0) from 47 contributors. There needs to be a special mention to [@MakeNowJust](https://github.com/MakeNowJust), [@straight-shoota](https://github.com/straight-shoota), [@Sija](https://github.com/Sija) and [@bew](https://github.com/bew) for their hard work in this release.

There were a ton of contributions merged in master even before 0.24.2 was released. But since 0.24.2 was already changing the release packaging for linux, changing the CI and fixing 0.24.1, some features needed to wait their turn a little longer.

Once again, we have tested this release by compiling some of the most popular crystal shards. This helps us catch and fix unintended breaking changes earlier in the release cycle as well as submitting PRs to the shards and contributing a bit more with the community. This process is codified using the scripts in the [test-ecosystem](https://github.com/bcardiff/test-ecosystem) repository, which is still fairly new, but so far it's working well.

The least visible work usually goes in infrastructure and there are always improvements and things waiting to be done. The latest news regarding this area are:

* Docs in master [are back](https://github.com/crystal-lang/crystal/pull/5941). For every PR that is merged the docs at HEAD can be found at [/api/master/](https://crystal-lang.org/api/master/).
* Improved SEO by adding a canonical url for online docs [#5990](https://github.com/crystal-lang/crystal/pull/5990).
* Also on docs, lots of improvements regarding navigation have been done in [#5229](https://github.com/crystal-lang/crystal/pull/5229).
* The automated release process now cares about 32 bits linux releases. As a bonus point the packaging has been aligned again with respect to the 64 bits packages. So some paths have changed.
* We've [been contacted](https://github.com/crystal-lang/heroku-buildpack-crystal/issues/30) by Heroku to early register our buildpack. Stay tuned to future Heroku news to update to the `crystal-lang/crystal` buildpack in the registry. All in all it's one more taste of the adoption of Crystal out there, and we are thrilled.

Nightly packages in `nightly.crystal-lang.org` are still down. The workaround for now it to use the docker image `crystallang/crystal:nightly`.


# Exciting features

## Shards is updated to 0.8.0

There are some performance improvements in shards for this release, by downloading less information when possible. A new global cache was added, so you don't need to download your favorite shards over and over on all of your favorites projects. FYI you can use shards 0.8.0 with Crystal 0.24.2 if you want.

Read more [here](https://github.com/crystal-lang/shards/releases/tag/v0.8.0).

## Automatic casts for literal values

If a method is defined as `def foo(x : Int8)` or `def bar(color : Color)` with

```ruby
enum Color
  Red
  Green
  Blue
end
```

up to 0.24 you would need to call them as `foo(1i8)` or `bar(Color::Blue)`. But since 0.25.0 you will be able to `foo(1)` and `bar(:blue)`. A note of caution: this only work with _literal values_. If the value is saved in a variable and used as an argument it won't work.

This feature allows cleaner code without sacrificing safety. Read more at [#6074](https://github.com/crystal-lang/crystal/pull/6074).

## User defined annotations and `[JSON|YAML]::Serializable`

This new language construct allows the user to define their own annotations, like `[Link]`. Basically you will be able to annotate types declaration or instance variables, and later on query them to do something you wish in macros.

Before this feature metaprogramming usually involved calling one macro with all the information needed. From now on, a more decoupled mechanism between declaring and consuming can be used. Read more at [#6063](https://github.com/crystal-lang/crystal/pull/6063).

The new `JSON::Serializable` and `YAML::Serializable` modules use this annotations. Feedback is welcome since this feature is brand new. You can read more at [#6082](https://github.com/crystal-lang/crystal/pull/6082), [JSON::Serializable](https://crystal-lang.org/api/JSON/Serializable.html), [YAML::Serializable](https://crystal-lang.org/api/YAML/Serializable.html) docs.

Another usage of annotations might be to declare a registry of classes, like the one used in `DB` drivers or frameworks handlers. And it could enable the removal of mutating values of constants during compilation time in favor of a more declarative code.

## Do not collapse unions for sibling types

Code is worth a thousand words (you know, like pictures):

```ruby
class Foo
end

class Bar < Foo
end

class Baz < Foo
end

var = rand < 0.5 ? Bar.new : Baz.new
typeof(var) #=> Bar | Baz
```

Up to 0.24.2 the result was `typeof(var) #=> Foo`.

Although the previous code already compiled fine in 0.24.2 this changes allow the type system to deal with some cases that would have ended in a compile-time error but that actually make sense. At the end of the day the type system is about identifying which programs will safely run and cutting the ones that won't.

The following program is an example of that. It won't compile in 0.24.2 but it now does in 0.25.0.

```ruby
class Foo
end

class Bar < Foo
  def do_it
  end
end

class Baz < Foo
  def do_it
  end
end

class Qux < Foo
  # there is no do_it
end

var = rand < 0.5 ? Bar.new : Baz.new
var.do_it
```

This is particularly useful in scenarios where there is a huge hierarchy of types but in a section of the code only a subset is used.

You can read more at [#6024](https://github.com/crystal-lang/crystal/pull/6024) and discover when the union of types are still collapsed to the common ancestor (spoiler, they need to not be siblings).

## `JSON::Any` and `YAML::Any` changes

There were some subtle inconsistencies with `JSON::Any` and `YAML::Any` API. The bottom line is that over an `::Any` value you can use `#[]` to traverse it and it will _always_ return an `::Any` value. If you need a specific type for the `::Any` value (and be able to use `Enumerable` methods if it was an array) you need to call the already known `#as_a`, `#as_h`, `#as_s` methods.

We still encourage, when possible, the use of `JSON.mapping`, `JSON::Serializable` or `JSON::PullParser` when finer control is needed.

Read more at [#5183](https://github.com/crystal-lang/crystal/pull/5183) and in the [JSON::Any](https://crystal-lang.org/api/JSON/Any.html) and [YAML::Any](https://crystal-lang.org/api/YAML/Any.html) docs.

## `HTTP::Server` can bind to multiple addresses

This will break lots of presentations and even [the code shown in our own homepage](https://github.com/crystal-lang/crystal-website/pull/63) but the benefits are great.

From now on if you use the built-in `HTTP::Server` you first need to configure it, then bind to one or more addresses, and lastly you listen to all of them. These addresses can be TCP ports or Unix sockets.

```ruby
require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world, got #{context.request.path}!"
end

server.bind_tcp "0.0.0.0", 8080
server.bind_unix "/tmp/app.sock"
server.listen
```

There is still a shortcut to bind and listen, but it doesn't avoid a breaking change. Read more at [#5776](https://github.com/crystal-lang/crystal/pull/5776), [#5959](https://github.com/crystal-lang/crystal/pull/5959), and the [HTTP::Server](https://crystal-lang.org/api/HTTP/Server.html) docs

## Welcome to the TimeZone Jungle

There was a huge refactor in `Time`. If you hit a unicorn while opening [the PR](https://github.com/crystal-lang/crystal/pull/5324) to read more about it, just try again.

Starting now `Time` has `#location` and `#offset` properties to know the timezone exactly. `Time.now` and `Time.new` will return by default information in the local timezone, while `Time.utc_now` and `Time.utc` will return information in UTC.

Methods like `#to_local`, `#to_utc`, `#utc?`, `#local?` and `#in(location : Location)` will help you to move around the globe faster than a plane.

The API even allows you to use custom timezones and fixed offsets with `Time::Location.fixed`.

Another change in the `Time` namespace are formatters. Better formatters for ISO 8601, RFC 3339, RFC 2822, HTTP enconded dates, YAML and other places where time was parsed or emitted now use a custom time formatter that deals with more cases as expected in each scenario.

Read more at [#5324](https://github.com/crystal-lang/crystal/pull/5324) and [#5123](https://github.com/crystal-lang/crystal/pull/5123) and [Time](https://crystal-lang.org/api/Time.html), and [Format](https://crystal-lang.org/api/Time/Format.html) docs.

## Replace `File::Stat` with `File::Info` and other file API changes

Some time ago an abstraction for the running OS was introduced in the stdlib. The goal was to be able to run the Crystal compiler in a non POSIX platform and keep the stdlib as clean as possible. Feel free to check [src/crystal/system](https://github.com/crystal-lang/crystal/tree/master/src/crystal/system), but keep in mind it is not intended as a public API.

This also required to pick names and abstractions in the stdlib that will fit everybody: POSIX and non POSIX.

The API was renamed and reworked for compare operations and accessing file properties and permissions. It is much clearer now. Hopefully it doesn't affect too many users, since most of us use `File.open`, `File.write` and move on. Read more at [#5584](https://github.com/crystal-lang/crystal/pull/5584), [#5333](https://github.com/crystal-lang/crystal/pull/5333), [#5553](https://github.com/crystal-lang/crystal/pull/5553), [#6161](https://github.com/crystal-lang/crystal/pull/6161), [File](https://crystal-lang.org/api/File.html) and [File::Info](https://crystal-lang.org/api/File/Info.html) docs.

## Heredoc on every argument

If you use Heredoc a lot of you might be interested in this one. Up to 0.24.2 if you wanted to call a method on a string specified using Heredoc you would do:

```ruby
puts <<-FOO
  message
  FOO.downcase
```

From now on the method needs to be at the initial delimiter

```ruby
puts <<-FOO.downcase
  message
  FOO
```

It's subtle but important, and it plays better with multiple Heredocs in a single call now that you can:

```ruby
puts <<-ONE.upcase, <<-TWO.capitalize
  hello world
  ONE
  second message
  TWO
```

Read more at [#5578](https://github.com/crystal-lang/crystal/pull/5578).

## Macro verbatim blocks

If you deal with escaped macros don't miss [#6108](https://github.com/crystal-lang/crystal/pull/6108).

Macros are powerful and they should be used _after_ there is a boilerplate pattern discovered.

This new language construct helps when the macro itself will define, for example, methods that have macro blocks that should be expanded later (i.e. nested macros).

It may result in a nicer way to express the same things you could before with some `{% raw %}\{% escaping %}{% endraw %}`.

# Other notable changes (breaking or not)

* `crystal deps` is dead, long live `shards install`. [#5544](https://github.com/crystal-lang/crystal/pull/5544). Unless we removed it, you would never have updated [your build scripts](https://github.com/crystal-lang/heroku-buildpack-crystal/commit/b85da4da408e45770922715288b80dc089568e08).
* Use `Hash#key_for` to perform a reverse lookup in a hash [#5444](https://github.com/crystal-lang/crystal/pull/5444) #NamesAreHard.
* The block argument from `loop` was removed [#6026](https://github.com/crystal-lang/crystal/pull/6026).
* Fix `File.join` with empty path component [#5915](https://github.com/crystal-lang/crystal/pull/5915).
* `Colorize#push` is dead, long live `Colorize#surround`[#4196](https://github.com/crystal-lang/crystal/pull/4196). Bonus point, your `#to_s` can use your favorite color now.
* Punycode is a special encoding used to convert Unicode characters to ASCII and is used to encode internationalized domain names (IDN). And now they are available in Crystal thanks to [#2543](https://github.com/crystal-lang/crystal/pull/2543).
* `pp` no longer prints the expression. But `pp!` and the new `p!` will. `p` stands for print, `pp` for pretty print and `!` for show me the ~~money~~ expression [#6044](https://github.com/crystal-lang/crystal/pull/6044).

# Next step

Please update your Crystal and report any issues. If there are regression or blocking issues with 0.25.0, a 0.25.1 could be released earlier.

Don't miss the rest of the [release changelog](https://github.com/crystal-lang/crystal/releases/tag/0.25.0) information with lots of other fixes.

> **THANKS:**
> The development is possible thanks to the community's effort, [84codes](https://www.84codes.com/)' support, and every [BountySource supporter](https://crystal-lang.org/sponsors).
