Ary Borenzweig 22 Nov 2016

Crystal 0.20.0 released!

Crystal 0.20.0 has been released!

Aside from the usual bugfixes and some performance improvements there’s a lot of new stuff here.

Shards 0.7.0

Crystal 0.20.0 comes with version 0.7.0 of shards, mostly maintained by Julien Portalier, whichs has a few new goodies like a build command and informational crystal (version) and libraries entries in the shard.yml file. Support for GitLab dependencies was also added.

Line and file number information in backtraces

Julien Portalier also added line and file number information to exception backtraces when programs are compiled with -d or --debug. For example:

# example.cr

def foo
  bar
end

def bar
  raise "OH NO!"
end

foo

Compiling and running:

$ crystal build example.cr -d
$ dsymutil --flat example # only needed on Mac OSX
$ ./example
OH NO! (Exception)
0x434f00: *bar:NoReturn at /opt/crystal/example.cr 8:3
0x434ee6: ??? at /opt/crystal/example.cr 4:3
0x431273: ??? at /opt/crystal/example.cr 11:1
0x434da9: main at /root/.cache/crystal/macro93695696.cr 12:15
0x7f9c98798f45: __libc_start_main at ??
0x430c29: ??? at ??
0x0: ??? at ??

File, line and column numbers appear on the right side. There’s still some things to improve here, but this is definitely and improvement and now it’s so much easier to trace an exception back to the source code.

ARM and AArch64 support

Julien Portalier is also the one who added support for these platforms.

LLVM 3.9 support

By… guess who? Julien Portalier once again! If we had something like “Crystal Awards”, well, now we know who would get the first place prize, right? ;-)

HTTP client and server streaming

Before 0.20.0 an HTTP::Server handler would receive a request with its entire body already loaded in memory. This wasn’t optimal, as maybe the body is needed, or it needs to be streamed. 0.20.0 introduces this (breaking) change. So, for example, one can stream a request directly into a JSON-mapped object, thus avoiding many intermediate memory allocations. For example:

require "http/server"
require "json"

class Point
  JSON.mapping x: Float64, y: Float64
end

# Accepts a JSON object representing a point and
# returns its absolute value (distance)
server = HTTP::Server.new(4567) do |context|
  request, response = context.request, context.response
  body = request.body
  if body
    point = Point.from_json(body)
    abs = Math.sqrt(point.x ** 2 + point.y ** 2)
    response.content_type = "application/json"
    {abs: abs}.to_json(response)
  else
    response.status_code = 400 # bad request
    response.content_type = "text/plain"
    response.puts "Missing body"
  end
end
puts "Listening on port 4567"
server.listen

And then:

$ curl localhost:4567 -XPOST --data '{"x": 3, "y": 4}'
{"abs":5.0}

Also, an IO can be passed into an HTTP::Client when perfoming a POST or PUT, so you can now upload a file very easily:

require "http/client"

response = File.open("some_file.txt") do |file|
  HTTP::Client.post("http://example.com", body: file)
end

Unicode aware methods for String and Char

Methods like String#downcase and String#upcase are now unicode aware.

Where previously a program behaved like this:

"RubyConf 2016 at São Paulo was awesome!".upcase
  # => "RUBYCONF 2016 AT SãO PAULO WAS AWESOME!"

(notice the small ‘ã’)

Now it behaves correctly:

"RubyConf 2016 at São Paulo was awesome!".upcase
  # => "RUBYCONF 2016 AT SÃO PAULO WAS AWESOME!"

This of course works for any language, and even some complex ligatures are handled:

"ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЁЯЧСМИТЬБЮ".downcase
  # => "йцукенгшщзхъфывапролджэёячсмитьбю"
"baffle".upcase # => "BAFFLE"

(The last example has ‘ffl’, which is a single character, but expands to three when upcased)

And even turkic is supported, where uppercase “i” is “İ” (an “I” with a dot):

"aeıiou".upcase(Unicode::CaseOptions::Turkic)
  # => "AEIİOU"

Random enhancements

These are not random enhancements, but rather enhancements to the Random module. Specifically, the ability to generate random integers of any type and any range, without overflow issues.

rand(Int64::MIN..Int64::MAX) # => 4544345849288905241

Thank you Oleh Prypin for another excellent contribution!

Optimized Array#sort

Tatsujin Chin sent a PR that replaces the old quicksort implementation with an introsort one. The end result is that this is now not only faster than the old implementation, but also faster than implementations in other languages, like c’s qsort and c++’s std::sort. Super thank you, Tatsujin Chin!

API docs have a nicer style

The style improvements include font changes and layout fixes. Take a look!

Special handling of common comments like TODO, OPTIMIZE and DEPRECATED was also added, and is now shown highlighted. Thank you Sam Eaton!

And more…

Make sure to read the full changelog for all the details, and upgrade instruccions due to some breaking changes.

We’d also like to thank everyone else that made this release possible with their contributions, reviews and suggestions.