Rocks
Brian J. Cardiff
bcardiff@manas.tech
19-Sept-19 @NardozBA@CrystalLanguage
Queremos un lenguaje
● Cómodo y seguro para el programador
● Cómodo para la máquina
Crystal
Syntaxis amena
# file: beetle.cr
3.times do
puts "Beetlejuice!"
end
$ crystal beetle.cr
Beetlejuice!
Beetlejuice!
Beetlejuice!
$ crystal build beetle.cr -o beetle
$ ./beetle
Beetlejuice!
Beetlejuice!
Beetlejuice!
$ otool -L ./beetle
./bettle:
/usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version
1.1.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
version 1252.250.1)
Compilado
$ crystal build --emit llvm-ir --no-debug beetle.cr
$ cat beetle.ll
@"'Beetlejuice!'" = private constant { i32, i32, i32, [13 x i8] } { i32 1, i32 12, i32 12,
[13 x i8] c"Beetlejuice!00" }
define void @__crystal_main(i32 %argc, i8** %argv) {
alloca:
%i = alloca i32
; ...
while:
%68 = load i32, i32* %i
%69 = icmp slt i32 %68, 3
br i1 %69, label %body, label %exit
body:
Compilado (via LLVM)
Compilado (via LLVM)
while:
%68 = load i32, i32* %i
%69 = icmp slt i32 %68, 3
br i1 %69, label %body, label %exit
body:
%70 = load i32, i32* %i
call void @"*puts<String>:Nil"(%String* bitcast ({ i32, i32, i32, [13 x i8] }*
@"'Beetlejuice!'" to %String*))
%71 = load i32, i32* %i
%72 = add i32 %71, 1
store i32 %72, i32* %i
br label %while
exit:
ret void
$ crystal build --emit asm --no-debug beetle.cr
$ cat beetle.s
LBB0_60:
cmpl $3, 52(%rsp)
jge LBB0_62
leaq "l_'Beetlejuice!'"(%rip), %rax
movq %rax, %rdi
callq "_*puts<String>:Nil"
movl 52(%rsp), %ecx
addl $1, %ecx
movl %ecx, 52(%rsp)
jmp LBB0_60
LBB0_62:
Compilado (via LLVM)
Evitar errores en runtime
puts "Hello Beetlejuice !".upper_case
$ crystal build beetle.cr
In beetle.cr:2:27
2 | puts "Hello Beetlejuice !".upper_case
^---------
Error: undefined method 'upper_case' for String
puts "Hello Beetlejuice !".upcase
$ crystal build beetle.cr
$ ./beetle
Hello Beetlejuice !
Evitar errores en runtime
# file: input.cr
name = gets
puts "Hello #{name.upcase} !"
$ crystal build input.cr
Evitar errores en runtime
# file: input.cr
name = gets
puts "Hello #{name.upcase} !"
$ crystal build input.cr
In input.cr:3:20
3 | puts "Hello #{name.upcase} !"
^-----
Error: undefined method 'upcase' for Nil (compile-time type is (String | Nil))
Evitar errores en runtime
Anotaciones de tipos (methods)
def greet(h)
n = h.name
puts "Hey #{n}! How are you #{n}?"
end
humans = [Human.new("Hiccup")]
greet(humans.first)
def greet(h : Human)
n : String
n = h.name
puts "Hey #{n}! How are you #{n}?"
end
humans = [Human.new("Hiccup")] of Human
greet(humans.first)
Anotaciones de tipos (methods)
Anotaciones de tipos (methods)
def greet(h)
...
humans = [] of Human
greet(humans.first) # (Runtime) Index out of bounds (IndexError)
greet(humans.first?) # (Compile) undefined method 'name' for Nil
def greet(h : Human)
...
greet(humans.first) # (Runtime) Index out of bounds (IndexError)
greet(humans.first?) # (Compile) no overload matches 'greet' with type
(Human | Nil)
class Dragon
def meet(h : Human)
puts "Bite"
end
def meet(d : Dragon)
puts "Play"
end
end
class Human
def meet(h : Human)
puts "Hi #{h.name}, I'm #{name}"
end
def meet(d : Dragon)
puts "Watch & train #{d.name}"
end
end
Multi-dispatch & “duck-typing”
creatures = [Human.new("Hiccup"), Human.new("Astrid"),
Dragon.new("Toothless"), Dragon.new("Fireworm")]
a, b = creatures.sample(2) # => a, b : Human | Dragon
print "#{a.name} meeting #{b.name}: "
a.meet(b)
class Human
@name : String
def initialize(name)
@name = name
end
def name
@name
end
end
Anotaciones de tipos (classes)
class Human
def initialize(@name : String)
end
def name
@name
end
end
class Box(T)
def initialize(@object : T)
end
# Returns the original object
def object : T
@object
end
end
Anotaciones de tipos (generics)
● Heap vs Stack
○ class Vec3
○ struct Vec3
● Stream oriented API
○ puts "Hi #{h.name}!"
○ cout << "Hi " << h.name << "!" (c++ vs alloc intermediate string)
○ def to_s(io : IO) : Nil
● Avoid intermediate allocations
○ JSON::Builder
Aprovechar Recursos
channel = Channel(Int32).new
total_lines = 0
files = Dir.glob("*.cr")
files.each do |f|
spawn do
lines = File.read(f).lines.size
channel.send lines
end
end
files.size.times do
total_lines += channel.receive
end
puts total_lines
Concurrencia
● Fibers (coroutines)
● Managed thread(s) worker(s)
● Blocking API (no callbacks)
“Do not communicate by sharing memory;
instead, share memory by communicating.”
Effective Go
https://golang.org/doc/effective_go.html#sharing
class Object
macro property(name)
@{{name.var}} : {{name.type}}
def {{name.var}} : {{name.type}}
@{{name.var}}
end
def {{name.var}}=(@{{name.var}} : {{name.type}})
end
end
end
Metaprogramación
class Human
property name : String
def initialize(@name)
end
end
Integración con C
// C
double cos(double x);
double y = cos(1.5);
# Crystal
lib C
fun cos(x : Float64) : Float64
end
y = C.cos(1.5)
@[Link("pcre")]
lib LibPCRE
type Pcre = Void*
fun compile = pcre_compile(
pattern : UInt8*,
options : Int,
errptr : UInt8**,
erroffset : Int*,
tableptr : Void*) : Pcre
end
Elecciones en Crystal
● Syntaxis amena
● Compilado
● Evitar errores en runtime cuando se pueda
● Multi-dispatch
● Estáticamente tipado pero con inferencia y “duck-typing”
● Promover buenas prácticas de uso de recursos
● Modelo de programación concurrente
● Metaprogramación
● Integración con C
● from a DB to JSON with Crystal
○ https://manas.tech/blog/2017/01/16/from-a-db-to-json-with-crystal.html
○ https://github.com/crystal-lang/crystal-db
● https://kemalcr.com/
● https://amberframework.org/
● https://luckyframework.org
● samples/2048.cr https://github.com/crystal-lang/crystal/tree/master/samples
● sdl raytracer https://github.com/asterite/crystal_sdl2_examples
● nes https://github.com/asterite/nes.cr
Apps & Frameworks
crystal-lang.org
¿Dónde?
Brian J. Cardiff
bcardiff@manas.tech
¡gracias!

Crystal Rocks

  • 1.
  • 2.
    Queremos un lenguaje ●Cómodo y seguro para el programador ● Cómodo para la máquina Crystal
  • 3.
    Syntaxis amena # file:beetle.cr 3.times do puts "Beetlejuice!" end $ crystal beetle.cr Beetlejuice! Beetlejuice! Beetlejuice!
  • 4.
    $ crystal buildbeetle.cr -o beetle $ ./beetle Beetlejuice! Beetlejuice! Beetlejuice! $ otool -L ./beetle ./bettle: /usr/lib/libpcre.0.dylib (compatibility version 1.0.0, current version 1.1.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.250.1) Compilado
  • 5.
    $ crystal build--emit llvm-ir --no-debug beetle.cr $ cat beetle.ll @"'Beetlejuice!'" = private constant { i32, i32, i32, [13 x i8] } { i32 1, i32 12, i32 12, [13 x i8] c"Beetlejuice!00" } define void @__crystal_main(i32 %argc, i8** %argv) { alloca: %i = alloca i32 ; ... while: %68 = load i32, i32* %i %69 = icmp slt i32 %68, 3 br i1 %69, label %body, label %exit body: Compilado (via LLVM)
  • 6.
    Compilado (via LLVM) while: %68= load i32, i32* %i %69 = icmp slt i32 %68, 3 br i1 %69, label %body, label %exit body: %70 = load i32, i32* %i call void @"*puts<String>:Nil"(%String* bitcast ({ i32, i32, i32, [13 x i8] }* @"'Beetlejuice!'" to %String*)) %71 = load i32, i32* %i %72 = add i32 %71, 1 store i32 %72, i32* %i br label %while exit: ret void
  • 7.
    $ crystal build--emit asm --no-debug beetle.cr $ cat beetle.s LBB0_60: cmpl $3, 52(%rsp) jge LBB0_62 leaq "l_'Beetlejuice!'"(%rip), %rax movq %rax, %rdi callq "_*puts<String>:Nil" movl 52(%rsp), %ecx addl $1, %ecx movl %ecx, 52(%rsp) jmp LBB0_60 LBB0_62: Compilado (via LLVM)
  • 8.
    Evitar errores enruntime puts "Hello Beetlejuice !".upper_case $ crystal build beetle.cr In beetle.cr:2:27 2 | puts "Hello Beetlejuice !".upper_case ^--------- Error: undefined method 'upper_case' for String
  • 9.
    puts "Hello Beetlejuice!".upcase $ crystal build beetle.cr $ ./beetle Hello Beetlejuice ! Evitar errores en runtime
  • 10.
    # file: input.cr name= gets puts "Hello #{name.upcase} !" $ crystal build input.cr Evitar errores en runtime
  • 11.
    # file: input.cr name= gets puts "Hello #{name.upcase} !" $ crystal build input.cr In input.cr:3:20 3 | puts "Hello #{name.upcase} !" ^----- Error: undefined method 'upcase' for Nil (compile-time type is (String | Nil)) Evitar errores en runtime
  • 12.
    Anotaciones de tipos(methods) def greet(h) n = h.name puts "Hey #{n}! How are you #{n}?" end humans = [Human.new("Hiccup")] greet(humans.first)
  • 13.
    def greet(h :Human) n : String n = h.name puts "Hey #{n}! How are you #{n}?" end humans = [Human.new("Hiccup")] of Human greet(humans.first) Anotaciones de tipos (methods)
  • 14.
    Anotaciones de tipos(methods) def greet(h) ... humans = [] of Human greet(humans.first) # (Runtime) Index out of bounds (IndexError) greet(humans.first?) # (Compile) undefined method 'name' for Nil def greet(h : Human) ... greet(humans.first) # (Runtime) Index out of bounds (IndexError) greet(humans.first?) # (Compile) no overload matches 'greet' with type (Human | Nil)
  • 15.
    class Dragon def meet(h: Human) puts "Bite" end def meet(d : Dragon) puts "Play" end end class Human def meet(h : Human) puts "Hi #{h.name}, I'm #{name}" end def meet(d : Dragon) puts "Watch & train #{d.name}" end end Multi-dispatch & “duck-typing” creatures = [Human.new("Hiccup"), Human.new("Astrid"), Dragon.new("Toothless"), Dragon.new("Fireworm")] a, b = creatures.sample(2) # => a, b : Human | Dragon print "#{a.name} meeting #{b.name}: " a.meet(b)
  • 16.
    class Human @name :String def initialize(name) @name = name end def name @name end end Anotaciones de tipos (classes) class Human def initialize(@name : String) end def name @name end end
  • 17.
    class Box(T) def initialize(@object: T) end # Returns the original object def object : T @object end end Anotaciones de tipos (generics)
  • 18.
    ● Heap vsStack ○ class Vec3 ○ struct Vec3 ● Stream oriented API ○ puts "Hi #{h.name}!" ○ cout << "Hi " << h.name << "!" (c++ vs alloc intermediate string) ○ def to_s(io : IO) : Nil ● Avoid intermediate allocations ○ JSON::Builder Aprovechar Recursos
  • 19.
    channel = Channel(Int32).new total_lines= 0 files = Dir.glob("*.cr") files.each do |f| spawn do lines = File.read(f).lines.size channel.send lines end end files.size.times do total_lines += channel.receive end puts total_lines Concurrencia ● Fibers (coroutines) ● Managed thread(s) worker(s) ● Blocking API (no callbacks) “Do not communicate by sharing memory; instead, share memory by communicating.” Effective Go https://golang.org/doc/effective_go.html#sharing
  • 20.
    class Object macro property(name) @{{name.var}}: {{name.type}} def {{name.var}} : {{name.type}} @{{name.var}} end def {{name.var}}=(@{{name.var}} : {{name.type}}) end end end Metaprogramación class Human property name : String def initialize(@name) end end
  • 21.
    Integración con C //C double cos(double x); double y = cos(1.5); # Crystal lib C fun cos(x : Float64) : Float64 end y = C.cos(1.5) @[Link("pcre")] lib LibPCRE type Pcre = Void* fun compile = pcre_compile( pattern : UInt8*, options : Int, errptr : UInt8**, erroffset : Int*, tableptr : Void*) : Pcre end
  • 22.
    Elecciones en Crystal ●Syntaxis amena ● Compilado ● Evitar errores en runtime cuando se pueda ● Multi-dispatch ● Estáticamente tipado pero con inferencia y “duck-typing” ● Promover buenas prácticas de uso de recursos ● Modelo de programación concurrente ● Metaprogramación ● Integración con C
  • 23.
    ● from aDB to JSON with Crystal ○ https://manas.tech/blog/2017/01/16/from-a-db-to-json-with-crystal.html ○ https://github.com/crystal-lang/crystal-db ● https://kemalcr.com/ ● https://amberframework.org/ ● https://luckyframework.org ● samples/2048.cr https://github.com/crystal-lang/crystal/tree/master/samples ● sdl raytracer https://github.com/asterite/crystal_sdl2_examples ● nes https://github.com/asterite/nes.cr Apps & Frameworks
  • 24.
  • 25.