Brian J. Cardiff 14 Feb 2020

Crystal 0.33.0 released!

Crystal 0.33.0 has been released!

This release comes with bug fixes, stability of the std-lib & runtime, some awaited language features and lots of cleanup.

There are 117 commits since 0.32.1 by 29 contributors.

Let’s review some highlights in this release. But don’t miss out on the rest of the release changelog which has a lot of valuable information.

Language changes

The new select/timeout language construct allows you to perform a blocking channel operation but timeout after a specific amount of time. It was previously possible to do manually, but it required some boilerplate and a dedicated fiber. This is now possible while taking advantage of libevent directly.

select
when x = ch.receive
  puts "got #{x}"
when timeout(1.second)
  puts "timeout"
end

timeout is not a top-level method and is expected to be used only in a blocking select when condition (ie: without an else). Read more about timeout in select statements in #8506.

Macros

In the built-in macros the TypeNode#name got extended with a new overload that allows you to pick whether you want (or not) the generic arguments when getting the type’s name (default is to include them). Read more at #8483.

class Foo(T); end

module Bar::Baz; end

{{Bar::Baz.name}}                 # => Bar::Baz
{{Foo.name}}                      # => Foo(T)
{{Foo.name(generic_args: false)}} # => Foo

Compiler

There were some memory corruption bugs because we used memset and memcpy 32-bits primitives in 64-bits machines. They are now fixed in #8746.

Now, the default CRYSTAL_PATH gives precedence to ./lib over embedded std-lib so your shards can override some std-lib modules if needed. Read more at #8752.

We did some clean-ups and completely dropped the support for previously deprecated comma separators in enums. Read more at #8657.

Standard library

We took the time to do some clean-ups regarding various previously deprecated methods and modules. Some of them deprecated almost over a year ago. PartialComparable, Crypto::Bcrypt::Password#==, HTTP::Server::Response#respond_with_error, JSON::PullParser::Kind#==, Symbol#==(JSON::PullParser::Kind), JSON::Token#type, String#at, Time.new, Time.now, Time.utc_now, URI.escape, URI.unescape are really no longer available. Read more at #8646, #8596.

There are also some additions. Object#in?(collection) is analogous to Enumerable#includes?(obj) but with the receiver and argument swapped.

42.in?(0..100)         # => true
4242.in?(0..100)       # => false
:baz.in?(:foo, :bar)   # => false
:bar.in?({:foo, :baz}) # => false
:foo.in?([:foo, :bar]) # => true

Read more at #8720 and check many of the usages in the current std-lib at #8723.

Serialization

The JSON deserialization improved to work better with some union types in #8689 and the JSON::PullParser deals properly with overflows in #8698.

The dig? methods for JSON::Any and YAML::Any got fixed to avoid raising on non-structure values. Read more at #8745.

Files

How File, User and Group interact with each other keeps evolving to find a sweet spot. File::Info#owner, and File::Info#group are deprecated in favor of #owner_id, and #group_id. Read more at #8007.

Networking

The handling of IO got more robust to deal with some race conditions in multi-thread and avoid using invalid file descriptors in libevent after fork. Read more at #8707 and #8733.

OpenSSL::SSL::Socket was improved to deal with some misbehaving parties out in the wild. Read more at #8540.

Concurrency

Sometimes in generic types, using Nil might cause some glitches. Like in Array(Nil), how would you distinguish if #[]? returns the stored nil or the out-of-bounds value. Even though sometimes it is still useful to use Nil as a type argument like in Channel(Nil). Future(Nil) should now be working without surprises. Read more at #8650.

We’ve been paying attention to sporadic failures on the CI multi-thread jobs. Sometimes the specs need to be iterated since they were written with a different single-thread mindset. Read more at #8592, #8643, and #8724.

Runtime

IO::FileDescriptor.from_stdio now returns an IO with blocking mode depending on the type of the file descriptor used for STDIN, STDOUT and STDERR. Read more at #8787.

Some changes in the runtime should improve the error reporting and exception handling. Read more at #8728, #8499, #8743.

Another addition that will reduce some paper cuts is a new top-level exception handler reporting. Read more at #8735, #8791.

Sometimes puts and dprintf are used to print to STDOUT or STDERR. But the latter is not portable. Crystal::System.print_error was extended to handle printf-like format. So it should be used instead of dprintf usually. Read more at #8786.

Spec

Usually using specs the Spec::DotFormatter shows… dots! The Spec::JUnitFormatter is another option that is a good fit for richer reporting. It’s got improved with lots of information in #8599.

As a bonus point this reporting was integrated in our CircleCI jobs so we can get some concise reports of failures, slow test and other statistics in the test summary. Read more at #8617.

Doc generator

We finally settled to use :ditto: and :nodoc: for the doc generator. So you should always put the : around those words when documenting your code. Read more at #6362.

Platforms

Regarding Windows support there was some movement. A Windows CI using GitHub Actions was added in #8676 to help us move forward and not backwards. The system module in prelude was enabled in #8661. More specs got fixed to work in #8670. And a helper script to identify working std-lib specs was added in #8664.

Regarding Alpine we are now also running it in the CI in #7420 and you might have read about the Alpine Docker images we are now building since #8708.

We started to use lld instead of ld in Linux builds since it seems we were hitting some ld limitations. In case you experience them you might also want to move to lld. If it is available the Makefile will take care to use it. Read more at #8641.

Next steps

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

It will also be helpful if your shards are tested against Crystal nightly releases. Either Docker or Snap are the current channels to get them easily. This will help reduce the friction of a release while checking if the ecosystem is in good shape.

The upcoming 0.34 is likely to include an updated shards, so using nightly would help us to collect feedback from it.

We have been able to do all of this thanks to the continued support of 84codes, and every other sponsor. It is extremely important for us to sustain the support through donations, so that we can maintain this development pace. OpenCollective and Bountysource are two available channels for that. Reach out to crystal@manas.tech if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!