Ary Borenzweig 23 Jan 2016

Crystal 0.11.0 released!

Crystal 0.11.0 has been released!

This release comes with syntax and semantic changes that favor consistency, standard library refactors, many performance improvements and bug fixes. A new version of shards is included.

Read the full changelog here.

Syntax changes

Type declarations and uninitialized variables

Before this release, :: was used to declare the type of instance variables.

class Point
  @x :: Int32
  @y :: Int32
  # ...
end

Additionally, :: inside a method had the meaning of declaring a variable with uninitialized (unsafe) contents:

def method
  # Allocate stack memory, don't zero it
  buffer :: UInt8[1024]
end

This was confusing, as a same syntax had two meanings. Now, the :: syntax is gone. To declare the type of a variable you use a single colon (:):

class Point
  @x : Int32
  @y : Int32
  # ...
end

This is also consistent with the syntax of type restrictions:

def add(x : Int32, y : Int32) : Int32
  x + y
end

To declare a variable with uninitialized content you now do:

def method
  # Allocate stack memory, don't zero it
  buffer = uninitialized UInt8[1024]
end

which is much more explicit and clear.

Additionally, type annotations are now allowed in class and global variables.

To upgrade your code to this new syntax, just run crystal tool format on your project: the formatter still understand the old syntax and will modify your code to use the new syntax :-)

Heredocs

String heredocs are now more powerful and convenient: leading space is removed from heredoc lines according to the leading space of the closing delimiter. For example:

# Same as "Hello\n  world"
<<-STRING
  Hello
    world
  STRING

# Same as "  Hello\n    world"
<<-STRING
    Hello
      world
  STRING

The old behaviour was inconvenient because it forced you to write all content aligned to the left. For example:

class Program
  USAGE = <<-USAGE
Usage: crystal [command] [switches] [program file] [--] [arguments]

Command:
    init                     generate a new project
    ...
USAGE
end

Now you can write it like this:

class Program
  USAGE = <<-USAGE
    Usage: crystal [command] [switches] [program file] [--] [arguments]

    Command:
        init                     generate a new project
        ...
    USAGE
end

Thank you rhysd for suggesting this change.

Semantic changes

Previously, return could be used inside a captured block. For example:

def capture(&block : -> Int32)
  block
end

def method
  proc = capture do |x|
    return 10 if x == 1
    2
  end
end

A return usually returns from a method, bypassing the block, but in the case of a captured block the return just exited the block and gave it a value. This was inconsistent, so now you have to use next, which is the way you give a block it’s value in other situations. return will give an error in this case.

Standard library changes

A huge refactor has been done to HTTP::Server to support streaming and upgrading protocols.

Previously you would write a server like this:

HTTP::Server.new(8080) do |request|
  HTTP::Response.ok "text/plain", "Got #{request.path}!"
end

The problem with this approach is that there’s no way to stream content to the response body. Well, there was a way: you would set an IO as the response body, but this was awkward and complex.

Now the handler receives a context which includes a response object to which you can write to.

HTTP::Server.new(8080) do |context|
  context.response.content_type = "text/plain"
  context.response.print "Got #{context.request.path}!"
end

Streaming data is now super easy:

HTTP::Server.new(8080) do |context|
  context.response.content_type = "text/plain"
  10.times do |i|
    context.response.puts i
    context.response.flush
    sleep 1
  end
end

The above code will write the numbers from 0 to 9, waiting 1 second between each write.

Performance improvements

Before this release libpcl was used for fiber context switch. Now this is done with inline assembly, which not only frees us from libpcl, it also works much faster.

Additionally, URI.parse was rewritten by will to not use regular expressions, which gave it a huge performance improvement.

Bug fixes

The compiler’s code now does an initial pass to declare all classes, macros and methods. This got rid of many bugs that depended on order of declaration, forcing you to use some ugly workarounds.

Shards 0.6.0

ysbaddaden’s shards comes with two new commands: prune (removes extraneous libs) and init (creates an initial shard.yml), as well as some bug fixes. Read the changelog here.

Thank you!

We want to thank everyone that contributes, discusses, promotes and critizices this project. We never stop being amazed at how much you do and help us grow the community, slowly getting us to 1.0.

Happy crystaling!

Crystal 0.11.0 has been released!

This release comes with syntax and semantic changes that favor consistency, standard library refactors, many performance improvements and bug fixes. A new version of shards is included.

Read the full changelog here.

Syntax changes

Type declarations and uninitialized variables

Before this release, :: was used to declare the type of instance variables.

class Point
  @x :: Int32
  @y :: Int32
  # ...
end

Additionally, :: inside a method had the meaning of declaring a variable with uninitialized (unsafe) contents:

def method
  # Allocate stack memory, don't zero it
  buffer :: UInt8[1024]
end

This was confusing, as a same syntax had two meanings. Now, the :: syntax is gone. To declare the type of a variable you use a single colon (:):

class Point
  @x : Int32
  @y : Int32
  # ...
end

This is also consistent with the syntax of type restrictions:

def add(x : Int32, y : Int32) : Int32
  x + y
end

To declare a variable with uninitialized content you now do:

def method
  # Allocate stack memory, don't zero it
  buffer = uninitialized UInt8[1024]
end

which is much more explicit and clear.

Additionally, type annotations are now allowed in class and global variables.

To upgrade your code to this new syntax, just run crystal tool format on your project: the formatter still understand the old syntax and will modify your code to use the new syntax :-)

Heredocs

String heredocs are now more powerful and convenient: leading space is removed from heredoc lines according to the leading space of the closing delimiter. For example:

# Same as "Hello\n  world"
<<-STRING
  Hello
    world
  STRING

# Same as "  Hello\n    world"
<<-STRING
    Hello
      world
  STRING

The old behaviour was inconvenient because it forced you to write all content aligned to the left. For example:

class Program
  USAGE = <<-USAGE
Usage: crystal [command] [switches] [program file] [--] [arguments]

Command:
    init                     generate a new project
    ...
USAGE
end

Now you can write it like this:

class Program
  USAGE = <<-USAGE
    Usage: crystal [command] [switches] [program file] [--] [arguments]

    Command:
        init                     generate a new project
        ...
    USAGE
end

Thank you rhysd for suggesting this change.

Semantic changes

Previously, return could be used inside a captured block. For example:

def capture(&block : -> Int32)
  block
end

def method
  proc = capture do |x|
    return 10 if x == 1
    2
  end
end

A return usually returns from a method, bypassing the block, but in the case of a captured block the return just exited the block and gave it a value. This was inconsistent, so now you have to use next, which is the way you give a block it’s value in other situations. return will give an error in this case.

Standard library changes

A huge refactor has been done to HTTP::Server to support streaming and upgrading protocols.

Previously you would write a server like this:

HTTP::Server.new(8080) do |request|
  HTTP::Response.ok "text/plain", "Got #{request.path}!"
end

The problem with this approach is that there’s no way to stream content to the response body. Well, there was a way: you would set an IO as the response body, but this was awkward and complex.

Now the handler receives a context which includes a response object to which you can write to.

HTTP::Server.new(8080) do |context|
  context.response.content_type = "text/plain"
  context.response.print "Got #{context.request.path}!"
end

Streaming data is now super easy:

HTTP::Server.new(8080) do |context|
  context.response.content_type = "text/plain"
  10.times do |i|
    context.response.puts i
    context.response.flush
    sleep 1
  end
end

The above code will write the numbers from 0 to 9, waiting 1 second between each write.

Performance improvements

Before this release libpcl was used for fiber context switch. Now this is done with inline assembly, which not only frees us from libpcl, it also works much faster.

Additionally, URI.parse was rewritten by will to not use regular expressions, which gave it a huge performance improvement.

Bug fixes

The compiler’s code now does an initial pass to declare all classes, macros and methods. This got rid of many bugs that depended on order of declaration, forcing you to use some ugly workarounds.

Shards 0.6.0

ysbaddaden’s shards comes with two new commands: prune (removes extraneous libs) and init (creates an initial shard.yml), as well as some bug fixes. Read the changelog here.

Thank you!

We want to thank everyone that contributes, discusses, promotes and critizices this project. We never stop being amazed at how much you do and help us grow the community, slowly getting us to 1.0.

Happy crystaling!