Crystal

by Craig Buchek

St. Louis Ruby User Group

March 10, 2014

@CraigBuchek

Crystal Is Inspired by Ruby

If you know Ruby, it's easy to get started

Syntax is about 90% the same as Ruby

Semantics are about 80% the same as Ruby


(Differences mainly due to being compiled)


							class Foo(T)
							  property :bar
							  def initialize(@bar : T)
							  end
							end
							foo = Foo.new("string")
							puts foo.bar #=> "string"
							foo2 = Foo(Int).new(123)
							puts foo2.bar #=> 123
						

Crystal Is Compiled

No support for dynamic features:


  • define_method
  • method_missing
  • eval

Supported "dynamic" features:


  • instance_eval
  • responds_to?
  • macro

Binaries range from 100 KB to 20 MB

Crystal Is Fast

Compiles pretty quickly


  • Compiles itself in less than 45 seconds
  • My Date class takes less than 1 second

Binaries are fast


  • My Date specs run in about 7 milliseconds
  • Newing up 1 million objects: 30 ms
    • 275 ms in Ruby (including 120 ms startup time)

Compiles and runs quickly


  • Full test suite takes less than 60 seconds
    • 2200 specs
  • Standard lib test suite takes about 5 seconds
    • 500 specs

Compiling LLVM bytecode to assembler is multithreaded

Crystal Is Typed

Types are inferred in most cases


  • Including union types

Eliminates NullPointerException errors


							def nil_or_string
							  rand(2) == 0 ? nil : "string"
							end
							nil_or_string.capitalize #=> Compile error: undefined method 'capitalize' for Nil
						

Methods can have variants with different signatures



							struct Date
							  def initialize(year : Int, month : Int, day : Int, @calendar = Date::Calendar.default)
							    @jdn = @calendar.ymd_to_jdn(year, month, day).to_i64
							  end
							  def initialize(jdn : Int, @calendar = Date::Calendar.default)
							    @jdn = jdn.to_i64
							  end
							end
						

Empty arrays and hashes have to declare their type


							x = [1] # OK
							x = [1, 1.5, 'a', "abc"] # OK
							x = []  # Syntax Error
							x = [] of Int
							x = [] of String|Nil|Int32
							y = {} of Symbol => String
						

No support for send

Crystal Is High-Level

Based on the Ruby we love

Strong OOP

Strong sense of getting things right and no surprises

Crystal Is Low-Level

Easy to interface with C libraries


							lib LibReadline("readline")
							  fun readline(prompt : UInt8*) : UInt8*
							end
							module Readline
							  def self.readline(prompt)
							    line = LibReadline.readline(prompt)
							    line ? String.new(line) : nil
							  end
							end
						

C types


							lib C
							  fun atoi(str : UInt8*) : Int32
							  fun atoll(str : UInt8*) : Int64
							  fun atof(str : UInt8*) : Float64
							  fun strtof(str : UInt8*, endp : UInt8**) : Float32
							  fun sprintf(str : UInt8*, format : UInt8*, ...) : Int32
							end
						

Low-level types


  • Pointer
  • Reference
  • Value
  • Struct
  • enum

Crystal Is Innovative

Shorthand syntax for initializer params


							class URI
							  def initialize(@scheme, @host, @port, @path, @query_string)
							    @uri = "#{@scheme}://#{@host}:#{@port}/#{@path}?#{@query_string}"
							  end
							end
						

Macros for getter, setter, property, and delegate



							class Object
							  macro self.getter(name)"
							    def #{name}
							      @#{name}
							    end
							  "end
							end
						

Hash initialization takes an optional key comparator



							h = Hash(String, Int).new(nil, Hash::CaseInsensitiveComparator)
							h["abc"] = 123
							puts h["AbC"] #=> 123
						

Block shorthand syntax



							[1, 20, 300].map &.to_s.length #=> [1, 2, 3]
						

Null checking



							method1.not_nil!.method2
						

Crystal Is Young

Started in September 2012

Standard library is somewhat minimal


  • Array, Hash, Set, Regex
  • Time, Env, File, Dir, Socket, MD5
  • Net::HTTP
  • JSON, YAML, XML
  • Missing: Date, Logger, Pathname

Spec library is minimal


  • describe
  • it
  • should

No database support

No Windows support

No debugger

REPL is a hack


  • Can't raise exceptions in some cases - just crashes
  • Anything with a side effect will be executed on every command
  • Several things just don't work

Crystal Is In Flux

Ported compiler from Ruby to self-hosting

They don't want to document too much


  • Because things are changing so fast

Things are broken sometimes


  • REPL was not compiling

Lots of changes in the past year


  • Garbage collection

Crystal Is Undocumented

Implicit conversions:


  • String to UInt8* for C functions
  • Nil to 0 for C functions taking a pointer

Class v. Struct

Syntax for complex types

No introspection

Crystal Is Full of Potential

I like what I see

I think it's pretty fast


  • The primary devs think it's too slow

Resources

Thanks

Primary Developers

Questions?