# A very basic HTTP serverrequire"http/server"server=HTTP::Server.newdo|context|context.response.content_type="text/plain"context.response.print"Hello world, got #{context.request.path}!"endaddress=server.bind_tcp(8080)puts"Listening on http://#{address}"# This call blocks until the process is terminatedserver.listen
Type system
Crystal is statically typed and type errors are caught early by the compiler,
eliminating a range of type-related errors at runtime.
Yet type annotations are rarely necessary, thanks to powerful type inference.
This keeps the code clean and feels like a dynamic language.
defshout(x)# Notice that both Int32 and String respond_to `to_s`x.to_s.upcaseend# If `ENV["FOO"]` is defined, use that, else `10`foo=ENV["FOO"]?||10putstypeof(foo)# => (Int32 | String)putstypeof(shout(foo))# => String
Null reference checks
nil values are represented by a special type, Nil, and any value that can be
nil has a union type including Nil.
As a consequence, the compiler can tell whether a value is nilable at compile
time. It enforces explicit handling of nil values, helping prevent the dreadful billion-dollar mistake.
foo=[nil,"hello world"].sample# The type of `foo` is a union of `String` and `Nil``putstypeof(foo)# => String | Nil# This would be a type error:# puts foo.upcase # Error: undefined method 'upcase' for Nil# The condition excludes `Nil` and inside the branch `foo`'s type is `String`.iffooputstypeof(foo)# => Stringputsfoo.upcaseend
Syntax
Crystal’s syntax is heavily inspired by Ruby’s, so it feels natural to read and easy to write, and has the added benefit of a lower learning curve for experienced Ruby devs.
Crystal uses green threads, called fibers, to achieve concurrency.
Fibers communicate with each other via channels without having to turn to shared memory or locks (CSP).
channel=Channel(Int32).new3.timesdo|i|spawndo3.timesdo|j|sleeprand(100).milliseconds# add non-determinism for funchannel.send10*(i+1)+jendendend9.timesdoputschannel.receiveend
C-bindings
Crystal allows to define bindings for C libraries and call into them.
You can easily use the vast richness of library ecosystems available.
No need to implement the entire program in Crystal when there are already
good libraries for some jobs.
# Define the lib bindings and link info:@[Link("m")]libLibMfunpow(x:LibC::Double,y:LibC::Double):LibC::Doubleend# Call a C function like a Crystal method:putsLibM.pow(2.0,4.0)# => 16.0# This example intentionally uses a simple standard C function to be succinct.# Of course you could do *this specific* calculation in native Crystal as well:# 2.0 ** 4.0 # => 16.0
Macros
Crystal’s answer to metaprogramming is a powerful macro system, which ranges from basic templating and AST inspection, to types inspection and running arbitrary external programs.