Crystal 0.34.0 has been released!
Get excited because this release comes with some of the final touches to the language before 1.0: a better exception hierarchy to replace Errno, a new logging module, cleanups and fixes aiming for a better, more stable release, one that should make us all proud.
There are 183 commits since 0.33.0 by 26 contributors.
Let’s get right into some of the highlights in this release. But don’t miss out on the rest of the release changelog which has a lot of valuable information.
From now on a
case expression will no longer have an implicit
else nil. This is useful to enable an exhaustive check across the
when branches within the
case. If you are doing
case exp over a union or an enum value, and you are missing a
when to cover some type or value, the compiler will let you know. Unless you have an
else at the end of the
Note: In this version, when the
case does not cover all the possibilities, a warning is generated, and the
else nil is implicitly added. In the next version it will produce a compile-time error and the implicit
else nil will be gone.
The following snippet complains about the missing
And the following snippet complains about the missing
The only case that will still have an implicit
else nil is when there is no expression and only a list of
when statements. This construction is equivalent to multiple
elseif where there is an implicit
else nil also.
Read more at #8424.
While dealing with
Procs and callbacks it is common to not use the return value. In Crystal, that usually means returning
nil. In regular methods you can specify the return type
: Nil to ignore the value of the last expression.
The counterpart in
Procs is harder because there usually is no type annotation for the return type.
For ease of use, we make it that any
Proc(T) should be able to be used as a
Proc(Nil). That is, ignoring the return value in runtime. So, for those that like formality,
Proc(T) < Proc(Nil) is a valid subtyping rule now.
There was a previous attempt to achieve something similar, but in this version, a better handling of that affair was implemented. Read more at #8970.
disable_overflow compiler flag is dropped. This means that the usual arithmetic operators will always have the overflow check. Use
&+ and others to skip overflow checks. Read more at #8772.
CRYSTAL_OPTS environment variable can now be used to inject compiler options and flags implicitly. This is useful, for example, when the compiler is used in
post_install steps of shards and you want to enforce
--error-on-warnings. Read more at #8900.
LLVM 10 has just been released and we added support for it. Read more at #8940.
The codegen for Windows has been improved to work without
--single-module. Read more at #8978.
A new version of Shards (0.10.0) has been released. Until now you probably have been using Shards 0.8.1 which lacks some features. Shards 0.9.0 polished many use cases, but it uses a SAT solver, which doesn’t scale. For Shards 0.10.0 we created crystal-molinillo a port of the dependency resolution algorithm used by Bundler and CocoaPods.
You can read the rest of the updates in the release changelog.
We will be eagerly waiting for feedback from you on Shards to polish it before 1.0.
Errno no more
Having as much as possible portable code is part of the goal of the std-lib. One of the areas that were in need of polishing was how
WinError were handled. The
WinError exceptions are now gone, and were replaced by a new hierarchy of exceptions. Unfortunately, there is no easy way to make a smooth transition here with deprecation warnings. The
IO::Timeout exception was renamed to
IO::TimeoutError to match the new hierarchy:
So, you can now use these new types to catch specific errors instead of checking
Errno values. We included the most used errors as classes. If there is no specific class, the base
Socket::Error will be raised with a meaningful description.
WinError underlying value is still present if you need it, via the
SystemError module included in this new hierarchy. But it is better if you avoid using it.
Read more at #8885.
Logger module is deprecated and will be removed soon. Its replacement is the
Log module: it’s shorter, more flexible and convenient.
You can use the top-level
Log constant to emit log entries, or you can declare one inside your module or class. This allows the entries to be emitted from a source.
Each source will be configured to send the entries to different backends depending on the severity level. If you initialize the logging with
Log.setup_from_env you will be able to filter the level and the sources using the
CRYSTAL_LOG_SOURCES environment variables.
If you want to log see all the log entries of the app above, you will need to set both environment variables, since their default values are
CRYSTAL_LOG_SOURCES="" (only top-level).
$ CRYSTAL_LOG_LEVEL=DEBUG CRYSTAL_LOG_SOURCES="*" ./app D, [2020-03-30T21:54:50.079554000Z #26206] DEBUG -- app:my_app: the app is running I, [2020-03-30T21:54:50.079624000Z #26206] INFO -- app:: finished
Top level cleanup
As we prepare for 1.0, we wanted to iterate and clean up some of the top-level of the std-lib and prelude. That is the reason behind many deprecations that involved part of
Colorize in #8892,
Iconv in #8890,
There might be some more cleanups/renames before 1.0 to avoid wanting some trivial early breaking-changes.
On the performance corner of this release, when using
Array#fill for writing all zero values, it will now use
memset for the entire underlying buffer, instead of iterating every position. Read more at #8903.
There is a small breaking change in
YAML in order to align the API of all builders.
YAML::Builder.new with block was renamed to
YAML::Builder.build in #8896.
When using the different format builders,
IO#flush will be called to ensure all the content will get through in case you are not closing properly the destination file. This applies to
YAML builders. Read more at #8876.
It’s time for more breaking-changes in favor of less error-prone code. The
Time::Span initialization API will use mandatory named arguments, like
Time::Span.new minutes: 2, seconds: 3. Read more at #8257.
When closing a
Socket the internal
fd is set to
-1 to force an invalid file descriptor and avoid mixing
fd from different
IOs. In single-thread, this was never an issue, but on multi-thread, as usual, issues like this one can cause big headaches. Read more at #8873.
IO::Buffered#flush_on_newline is back. And its default value will be helpful for building CLI tools and pipe them into other commands. Read more at #8935.
The WebSocket support was lacking the proper handling of close code. In order to implement them, a breaking-change on the server-side and in client-side parts was needed. Read more at #8975 and #8981.
crystal docs tool will now show warnings. In previous releases we switched to
:nodoc: as magic comments. But we missed showing you the warnings in case you forget to add the colons. Read more at #8880.
Please update your Crystal and report any issues. We will keep moving forward and start the development focusing on 0.35. There won’t be many more 0.x releases. We are getting super close to 1.0!.
Again, we will be eagerly waiting for feedback from you on Shards to polish it before 1.0.
All deprecation warnings will soon be gone, and there will be errors in the next release. We want a clean 1.0.
We have been able to do all of this thanks to the continued support of 84codes, Nikola Motor Company 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 firstname.lastname@example.org if you’d like to become a direct sponsor or find other ways to support Crystal. We thank you in advance!