Crystal:
A language for humans and computers

Beta Ziliani – Crystal Core Team / Manas.Tech

Agenda

  • Hello World
  • Crystal primer
  • Open Source and Crystal
qr code

Beta Ziliani
Manas.Tech

beta@manas.tech

github: @bziliani

mastodon: @beta@types.pl

Follow the slides


crystal-lang.org/install | play.crystal-lang.org

Benefits of Crystal

  • Inherited a lot of goodies from Ruby
  • User-friendly syntax
  • Versatile and productive
  • Simple and intuitive
  • Static typing with type inference
  • Compiles to highly efficient machine code
  • Strong, intuitive concurrency model

Install

crystal-lang.org/install
$ crystal --version
            Crystal 1.13.3 (2024-09-18)

            LLVM: 18.1.8
            Default target: x86_64-unknown-linux-gnu
          

Hello, World

# src/hello.cr
puts "Hello, Crystal!"
$ crystal src/hello.cr
Hello, Crystal!

Batteries included

# A very basic HTTP server
require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello, Crystal!"
end

address = server.bind_tcp(8080)
puts "Listening on http://#{address}"

server.listen

$ crystal build --release src/http-server.cr

$ ./http-server &

$ wrk -t8 -c400 -d60s http://localhost:8080/
Running 1m test @ http://localhost:8080/
  8 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.11ms    1.09ms  17.66ms   79.34%
    Req/Sec     7.07k     1.15k   62.53k    85.64%
  3373196 requests in 1.00m, 334.56MB read
Requests/sec:  56126.81
Transfer/sec:      5.57MB
Competitive performance

Static Typing

  • Type safety
  • Feels dynamic
def add(a, b)
  a + b
end

add 1, 2 # => 3
add "foo", "bar" # => "foobar"

Static Typing

  • Type safety
  • Feels dynamic
def add(a, b)
  a + b
end

add 1, 2 # => 3
add "foo", "bar" # => "foobar"

add "foo", 2 # Error: instantiating 'add(String, Int32)
             # Error: expected argument #1 to 'String#+'
             # to be Char or String, not Int32

Static Typing

ary = [1, 2, 3]

ary.class # => Array(Int32)

ary << 4
typeof(ary[0]) # Int32

ary << "foo" # Error: expected argument #1 to 'Array(Int32)#<<'
             # to be Int32, not String

Static Typing

ary = [1, 2, 3] of Int32 | String

ary.class # => Array(Int32 | String)

ary << 4
typeof(ary[0]) # Int32 | String

ary << "foo"

Static Typing


        [] # Error: for empty arrays use '[] of ElementType'

        [] of String
        # or
        Array(String).new
        

Static Typing

instance variables

class Foo
  @bar = 123

  def initialize(@baz : String)
  end
end

Compilation

$ crystal build src/hello.crb

$ ls -sh hello
2,0M hello-world

$ file hello
hello: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d7768fdb368d11e8e08c9bcaea7cc1a629914f04, for GNU/Linux 3.2.0, with debug_info, not stripped

$ ./hello
Hello, Crystal!

Compilation

  • Runtime is embedded into the binary
  • LLVM backend generates efficient code
  • Limited dynamic language features

Metaprogramming: macro

Code that writes other code at compile time

macro getter(var)

  # macro body

end

getter foo

Macro expansion:


  # macro body

Metaprogramming: macro

Code that writes other code at compile time

macro getter(var)
  def {{ var.id }}
    @{{ var.id }}
  end
end

getter foo

Macro expansion:

def foo
  @foo
end

Metaprogramming: def

class Foo
  def ==(other)
    {% for ivar in @type.instance_vars %}
      return false unless @{{ivar.id}} == other.@{{ivar.id}}
    {% end %}
    true
  end
end

Macro expansion:

# macro expansion of method body with ivars @bar and @baz
    return false unless @baz == other.@baz
    return false unless @bar == other.@bar
    true

Concurrency

channel = Channel(Int32).new

3.times do |i|   # i = 0, 1, 2
  spawn do       # concurrently do...
    3.times do |j|
      sleep rand(100).milliseconds # add non-determinism for fun
      channel.send 10 * (i + 1) + j
    end
  end
end

9.times do
  puts channel.receive
end

Dependencies

# shard.yml
name: my-first-crystal-app
version: 1.0.0

dependencies:
  mysql:
    github: crystal-lang/crystal-mysql
    version: >=0.16.0
$ shards install
$ shards update

Open Source

  • Source code is publicly available
  • May be redistributed
  • May be modified
  • Associated with a community and external contributions

Contributing to Crystal

  • Crystal is on GitHub:
    https://github.com/crystal-lang/crystal

  • Fork:
    https://github.com/crystal-lang/crystal/fork
  • Make Crystal better in your fork
  • Read the contribution guidelines:
    https://github.com/crystal-lang/crystal/blob/master/CONTRIBUTING.md
  • Open a Pull Request and go through the review process
  • Was your Pull Request merged?
    Congrats, you are now officially a Crystal contributor!

Conclusion

  • Crystal lets you write expressive code to build easy to maintain and highly performant systems
  • Open source is a lot of fun but also a catalyzer of progress!

Expressivity

  • Expressivity comes largely as a (beloved <3) legacy from Ruby
  • Batteries included standard library + Terse code

Maintainability

  • Maintainability comes from stricter typing with a powerful inference engine that preserves expressivity
  • The compiler is your friend, it guides you through changes

Performance

  • Performance comes partly from using LLVM and partly from Crystal's team and community obsession with it since day zero ;o)

Open source

  • Crystal is open source, and it's written in... Crystal
  • Which means: once you learn Crystal, you can start contributing to making it!

Thank you

84codes Manas