@maiha
2016.11.29
Fast
Difficult (pointers)
Memory leaks
Easy (Readability, GC)
Slow
char *path = NULL;
if (config == NULL) {
fr = zmalloc(sizeof(*fr));
run_callback(void (*cb)
...require "redis"
redis = Redis.new
redis.get("foo")xxx BC
We want both!
Trade off
(cpu 0.000 total)
undefined method ...
from test.rb:8:in `<main>'but,Runtime Error
Engineers!
AD 199x
Fast!
AD 1999
Type and Compile!
JVM(jar)
JVM(null, type erasure)
No more null
No more JVM
No more work around
var user = new User
user = null // PASS
if (user != null) {
...
// jar returns nullOther languages
COOL!
We want both!
AD 200x
user = User.new
user = null // Compile error
Array(String).new // Keep typebut,No implements
Strictly Typed!
Academics!
on LLVM
(manas.tech)
AD 2012
GOD comes!
Really GOD!
Fast
null and pitfall free
def parse(email : String)
email.split("@",2)
end
parse(nil)
no overload matches 'parse'
with type Nil
Overloads are:
- parse(email : String)Easy
Type safety (compile-time)
Stable, CLang-friendly
Compile Error
Crystal
% crenv local 0.20.0% vi shard.yml
% shards update% crystal spec% crystal build foo.crKemalBoehm GC
bundled
bundled
foo.should eq(XXX)require "redis"
redis = Redis.new
redis.get("foo")Syntax
require "redis"
redis = Redis.new
redis.get("foo")def parse(email)
email.split("@", 2)
end
parse("a@b")
# => Arraydef parse(email)
email.split("@", 2)
end
parse("a@b")
# => Array(String)a = []
a = Array.new
h = {}
h = Hash.newType (Generic)
a = [] of String
a = Array(String).new
h = {} of String => Int32
h = Hash(String, Int32).newarray = [1, "a"]class Array(T)
include Enumerable(T)
class Hash(K, V)
include Enumerable({K, V})Tuple
t = [1, "a"]
# Array
t[0] # => 1 (Fixnum)
t[1] # => "a" (String)
t[2] # => nilt = {1, "a"}
# Tuple(Int32, String)
t[0] # => 1 (Int32)
t[1] # => "a" (String)
t[2] # index out of boundsCompile Error
X = Struct.new(:i, :s)
X.new(1, "a")
X.new(1, 2)record X,
i : Int32,
s : String
X.new(1, "a")
X.new(1, 2)Compile Error
Type Inference
def foo(a)
def foo(a) : Int32
def foo(a : String)
def foo(a : String) : Int32not supported yet
i : Int32 = 0class User
@name : String = "(no name)"
class User
def initialize(name : String)
@name = nameauto
required
Type Inference(2)
class User
def name
@name || "?"
end
end
User.new.namemust be initialized
Union Type(1)
def foo(a : Int32 | String)
def foo(a : Int32 | String | Array(Int32 | Int64))class Cache
def get(key)
if found
return value
else
return nil
# => (String | Nil)class Cache
def get(key) : String | Nil
class Cache
alias Result = String | Nil
def get(key) : Result
class Cache
def get?(key) : String?Union Type(2)
class Parser
def parse(str)
@parsed ||= "x" # [STUB]
@parsed.upcase
# undefined method 'upcase' for Nil
# (compile-time type is (String | Nil))
@parsed ||= "x" # [STUB]
@parsed # String | Nil
@parsed.not_nil! # String
@parsed.not_nil!.upcaseBlock
[1,2].map(&:to_s)[1,2].map(&.to_s)
[1,2].map(&.to_s.size)def foo(&block)def foo(&block)
def foo(&block : Int32 ->)
def foo(&block : -> String)
def foo(&block : Int32 -> String)Useful features
class User
def initialize(@name : String)
endbundled
Object#delegateObject#tryclass Foo::Bar
X # => ::X (ruby)
# => Foo::X (crystal)
endnice!
Macro
foo = 1
p foo1macro p(v)
puts "{{v.id}}: #{{{v}}.inspect}"
endfoo: 11→
v → Var("foo") < ASTNode
{{v.id}} →"foo"
{{v}} → foo
#{foo.inspect}
foo = 1
p foo→
pp bundled
CLang friendly
@[Link("foo")]
lib LibFoo
fun xxx(x0 : UInt32) : UInt32
end
p LibFoo.xxx(0_u32)JVM
→
LLVM
→
→
cc ... -lgc -lfooauto link
direct access!
CLang (auto gen)
@[Include("rocksdb/c.h", prefix: %w(rocksdb_))]
@[Link("rocksdb")]
lib LibRocksDB
endcrystal_lib
→
→
schema
code
crystal src/main.cr -- schema-filelib LibRocksDB
fun open = rocksdb_open(options : Rocksdb...
type RocksdbOptionsT = Void*Spec(1)
require "spec"
describe "Foo" do
it "bar" do
baz.should eq(XXX)
baz.should_not eq(XXX)
expect_raises(Foo::NotFound, "xxx") do
baz.get("x")
end
spec2
describe "Foo" do
subject { Foo.new }
let(key) { "x" }Spec(2)
describe "Foo" do
def setup
end
it "bar" do
setupspec2
describe "Foo" do
describe "(case 1)" do
it "" doprivate def setup
end
describe "Foo" do
it "bar" do
setupcompile error
→
compile error
Speed
good!
% crystal build --release foo.crStability
good!
no runtime errors! no memory leaks!
| python | crystal | redis | crystal | grafana |
|---|---|---|---|---|
| dstat | dstat-redis | (cluster) | grafana-redis | (http) |
10 servers, 300bytes(JSON),1qps
not yet
excellent!
kafka-ping, redis-cluster-managing, stress-testing
Stability (FYI)
be careful
libopenssl.a (ubuntu-16.04)
libxml2.a (ubuntu-16.04)
name = "foo"
printf("%i", name)invalid Int32: foo (ArgumentError)compile ok, but
2147483647 → -2147483648BUG
Deploy
ubuntu, CentOS, SL, ...
java versions, ruby version, maven is down, proxy,...
no chefs, no ansibles, ...
excellent!
compile
binary
host
→
→