SlideShare ist ein Scribd-Unternehmen logo
1 von 69
Downloaden Sie, um offline zu lesen
How to write Ruby
extensions with Crystal
@gaar4ica

Anna Shcherbinina
I like Ruby
5 YO, a lot of stuff
So, I like Ruby
But, sometimes,
I need my code to work
faster
def fibonacci(n)
n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
end
Case of possible bottle
neck
Ruby has C bindings
C is hard to learn and
understand
Static types Allocating 

memory
And tons of other
complications
for Ruby developer
I’m ruby developer,
I don’t want to write my code in C
I’m ruby developer,
I want to write my code in Ruby.
But to be honest…
Node.js
NET
OWL PDF
XML
Redis
C++
Scala
BASIC
C#
I’m ruby developer,
I want to write my code in Ruby
Also, I like Crystal
Crystal has ruby-like
Spoiler about crystal
Guess the language
# define class Dog
class Dog
def initialize(breed, name)
@breed = breed
@name = name
end
def bark
puts 'Ruff! Ruff!'
end
def display
puts "I am of #{@breed} breed and my name is #{@name}"
end
end

# make an object
d = Dog.new('Labrador', 'Benzy')
Crystal compiles to native
code
Spoiler about crystal
So, I like Crystal
No way
No way
?
C
bindings
C bindings
C layer
Link Crystal classes
and methods to Ruby,
so Ruby knows about
them
Translate 

Ruby-types 

to Crystal-types
So, Crystal lang
WUT?
Compile to efficient 

native code
Statically 

type-checked
Ruby-inspired 

syntax
C bindings
Web Frameworks
• amatista
• amethyst
• kemal
• moonshine
Testing
Search CacheDBDDBD
Third-party 

APIs
Libs
Ready for production or not?
Web apps Microservice
• maths calculation
• small but heavy parts of
projects
What for
Not so like ruby
if @a
# here @a can be nil
end
if @a.is_a?(String)
# here @a is not guaranteed to be a String
end
if @a.responds_to?(:abs)
# here @a is not guaranteed to respond to `abs`
end
The below doesn’t work with instance variables,
class variables or global variables.
Variables
Not so like ruby
To work with these, first assign them to a variable:
if a = @a
# here a can't be nil
end
# Second option: use `Object#try` found in the
standard library
@a.try do |a|
# here a can't be nil
end
if (a = @a).is_a?(String)
# here a is guaranteed to be a String
end
Variables
Not so like ruby
Classes and methods
Not so like ruby
Overloading Return types
Visibility Finalize
Macros
Not so like ruby
class Object
macro def instance_vars_names : Array(String)
{{ @type.instance_vars.map &.name.stringify }}
end
end
class Person
def initialize(@name, @age)
end
end
person = Person.new "John", 30
person.instance_vars_names #=> ["name", "age"]
Threads
Not so like ruby
def generate(chan)
i = 2
loop do
chan.send(i)
i += 1
end
end
def filter(in_chan, out_chan, prime)
loop do
i = in_chan.receive
if i % prime != 0
out_chan.send(i)
end
end
end
ch = Channel(Int32).new
spawn generate(ch)
100.times do
prime = ch.receive
puts prime
ch1 =
Channel(Int32).new
spawn filter(ch, ch1,
prime)
ch = ch1
end
Benchmarking
Time (s)
Go Erlang Crystal Scala Ruby C Crystal Ruby C Crystal Ruby
4.084.082.21
27.92
6.025.08
41.73
6.426.091.971.48
Memory (Mb)
Go Erlang Crystal Scala Ruby C Crystal Ruby C Crystal Ruby
162.40
1.400.40
115.50107.60
32.4030.00
1.505.3017.10
2.00
Threadring Binarytree Fast
Threadring Binarytree Fast
Back to case of
possible bottle neck
def fibonacci(n)
n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
end
Back to
C
bindings
Less work for C
Passing primitive data structures:
• integer
• string
• boolean
• float / decimal
• etc.
No allocation memory for complex data types
Don’t do a lot of work for casting variables passed as attributes
Ruby C API
Entry point
Then every C extension has to implement a function named
Init_xxxxx (xxxxx being your extension’s name).
It is being executed during the “require” of your extension.
void Init_xxxxx() {
// Code executed during "require"
}
Ruby C API
Types
Ruby C API defines a bunch of handful C constants defining
standard Ruby objects:
C Ruby
Qnil nil
Qtrue TRUE
Qfalse FALSE
rb_cObject Object
rb_mKernel Kernel
rb_cString String
Ruby C API
Declaring modules and classes
// Creating classes
// rb_define_class creates a new class named name
// and inheriting from super.
// The return value is a handle to the new class.
VALUE rb_define_class(const char *name, VALUE super);
// Creating modules
// rb_define_module defines a module whose name
// is the string name.
// The return value is a handle to the module.
VALUE rb_define_module(const char *name);
Ruby C API
Declaring methods
// Creating a method
// rb_define_method defines a new instance method in the class
// or moduleklass.
// The method calls func with argc arguments.
// They differ in how they specify the name - rb_define_method
// uses the constant string name
void rb_define_method(VALUE klass, const char *name, VALUE
(*func)(ANYARGS), int argc);
// rb_define_protected_method and rb_define_private_method are
similar to rb_define_method,
// except that they define protected and private methods,
respectively.
void rb_define_protected_method(VALUE klass, const char *name,
VALUE (*func)(ANYARGS), int argc);
void rb_define_private_method(VALUE klass, const char *name,
VALUE (*func)(ANYARGS), int argc);
Ruby C API
Ruby objects → C types
// Convert Numeric to integer.
long rb_num2int(VALUE obj);
// Convert Numeric to unsigned integer.
unsigned long rb_num2uint(VALUE obj);
// Convert Numeric to double.
double rb_num2dbl(VALUE);
// Convert Ruby string to a String.
VALUE rb_str_to_str(VALUE object);
char* rb_string_value_cstr(volatile VALUE* object_variable);
Ruby C API
C types → Ruby objects
// Convert an integer to Fixnum or Bignum.
INT2NUM( int );
// convert an unsigned integer to Fixnum or Bignum.
UINT2NUM( unsigned int );
// Convert a double to Float.
rb_float_new( double );
// Convert a character string to String.
rb_str_new2( char* );
// Convert a character string to ID (for Ruby function names,
etc.).
rb_intern( char* );
// Convert a character string to a ruby Symbol object.
ID2SYM( rb_intern(char*) );
Ruby C API
Simple example
# my_class.rb
class MyClass
def my_method(param1, param2)
end
end
// my_class_ext.c
static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE
rb_param2)
{
// Code executed when calling my_method on an object of class MyClass
}
void Init_xxxxx()
{
// Define a new class (inheriting Object) in this module
VALUE myclass = rb_define_class("MyClass", rb_cObject);
// Define a method in this class, taking 2 arguments,
// and using the C method "myclass_method" as its body
rb_define_method(myclass, "my_method", myclass_mymethod, 2);
}
Ruby C API
Simple example
# my_class.rb
class MyClass
def my_method(param1, param2)
end
end
// my_class_ext.c
static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE
rb_param2)
{
// Code executed when calling my_method on an object of class MyClass
}
void Init_xxxxx()
{
// Define a new class (inheriting Object) in this module
VALUE myclass = rb_define_class("MyClass", rb_cObject);
// Define a method in this class, taking 2 arguments,
// and using the C method "myclass_method" as its body
rb_define_method(myclass, "my_method", myclass_mymethod, 2);
}
Ruby C API
Simple example
# my_class.rb
class MyClass
def my_method(param1, param2)
end
end
// my_class_ext.c
static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE
rb_param2)
{
// Code executed when calling my_method on an object of class MyClass
}
void Init_xxxxx()
{
// Define a new class (inheriting Object) in this module
VALUE myclass = rb_define_class("MyClass", rb_cObject);
// Define a method in this class, taking 2 arguments,
// and using the C method "myclass_method" as its body
rb_define_method(myclass, "my_method", myclass_mymethod, 2);
}
def fibonacci(n)
n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
end
Back to case of possible 

bottle neck
And solution
C
A lib declaration groups C functions and types that belong to 

a library.
Crystal extension
It’s easy
lib CrRuby
type VALUE = Void*
$rb_cObject : VALUE
end
Every ruby object is treated as type VALUE in C.
Crystal extension
It’s easy
lib CrRuby
type VALUE = Void*
$rb_cObject : VALUE
end
rb_cObject is a C constant defining standard Ruby Object class.
Crystal extension
It’s easy
lib CrRuby
type VALUE = Void*
$rb_cObject : VALUE
end
lib CrRuby
type VALUE = Void*
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
end
A fun declaration inside a lib binds to a C function.
We bind rb_num2int & rb_int2inum, to use it later.
Crystal extension
It’s easy
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func:
METHOD_FUNC, argc: Int32)
end
Crystal extension
It’s easy
We bind rb_define_class & rb_define_method.
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
Our new and shiny fibonacci method in Crystal.
def fibonacci(n)
n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2)
end
Do you see the difference with implementation in Ruby?
Crystal extension
It’s easy
Crystal extension
It’s easy
Let’s create a wrapper for this method, used for:
• convert inbound Ruby-type parameter to Crystal;
• convert outbound result back to Ruby type.
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
Crystal extension
It’s easy
Now we are done with our functions and C bindings.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
Crystal extension
It’s easy
Now we are done with our functions and C bindings.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
Crystal extension
It’s easy
Now we are done with our functions and C bindings.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
Crystal extension
It’s easy
Now we are done with our functions and C bindings.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
Crystal extension
It’s easy
We bind init function, the first one to be called.
As you remember, a function named Init_xxxxx is being executed
during the “require” of your extension.
fun init = Init_cr_math
end
Crystal extension
It’s easy
Firstly, we start garbage collector.
We need to invoke Crystal's "main" function, the one that initializes all
constants and runs the top-level code.
We pass 0 and null to argc and argv.
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
end
Crystal extension
It’s easy
We define class CrMath.
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject)
CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1)
end
Crystal extension
It’s easy
We define class CrMath.
Attach method fibonacci to class.
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject)
CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1)
end
Crystal extension
Ready to compile
We have Crystal library with C bindings.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject)
CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1)
end
Crystal extension
Ready to compile
We have method fibonacci_cr and wrapper for it.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject)
CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1)
end
Crystal extension
Ready to compile
We have entry point.
lib CrRuby
type VALUE = Void*
type METHOD_FUNC = VALUE, VALUE -> VALUE
$rb_cObject : VALUE
fun rb_num2int(value : VALUE) : Int32
fun rb_int2inum(value : Int32) : VALUE
fun rb_define_class(name: UInt8*, super: VALUE) : VALUE
fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32)
end
def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE)
int_value = CrRuby.rb_num2int(value)
CrRuby.rb_int2inum(fibonacci_cr(int_value))
end
def fibonacci_cr(n)
n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2)
end
fun init = Init_cr_math
GC.init
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject)
CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1)
end
Crystal extension
Ready to compile
Makefile
CRYSTAL = crystal
UNAME = "$(shell uname -ms)"
LIBRARY_PATH = $(shell brew --prefix crystal-lang)/embedded/lib
TARGET = cr_math.bundle
$(TARGET): cr_math.o
$(CC) -bundle -L$(LIBRARY_PATH) -o $@ $^
cr_math.o: cr_math.cr
$(CRYSTAL) build --cross-compile $(UNAME) $<
$ irb
2.1.6 :001 > require './cr_math'
=> true
2.1.6 :002 > CrMath.new.fibonacci(20)
=> 6765
Crystal extension
Using in Ruby
# benchmark.rb
require 'benchmark'
require './cr_math' # We have compiled cr_math.bundle
require './rb_math'
iterations = 10_000
number = 20
Benchmark.bm do |bm|
bm.report("rb") do
iterations.times { RbMath.new.fibonacci(number) }
end
bm.report("cr") do
iterations.times { CrMath.new.fibonacci(number) }
end
end
# rb_math.rb
class RbMath
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) +
fibonacci(n - 2)
end
end
Crystal extension
Benchmarking
# benchmark.rb
require 'benchmark'
require './cr_math' # We have compiled cr_math.bundle
require './rb_math'
iterations = 10_000
number = 20
Benchmark.bm do |bm|
bm.report("rb") do
iterations.times { RbMath.new.fibonacci(number) }
end
bm.report("cr") do
iterations.times { CrMath.new.fibonacci(number) }
end
end
# rb_math.rb
class RbMath
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) +
fibonacci(n - 2)
end
end
Crystal extension
Benchmarking
$ ruby benchmark.rb
user system total real
rb 10.270000 0.030000 10.300000 ( 10.314595)
cr 0.460000 0.000000 0.460000 ( 0.464087)
Crystal extension
Benchmarking
Ta-Da!
Thank you
https://twitter.com/gaar4ica
https://github.com/gaar4ica/ruby_ext_in_crystal_math
http://crystal-lang.org/
https://github.com/manastech/crystal
https://github.com/5t111111/ruby_extension_with_crystal
http://blog.jacius.info/ruby-c-extension-cheat-sheet/

Weitere ähnliche Inhalte

Was ist angesagt?

プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造
Takuya Akiba
 

Was ist angesagt? (20)

よくわかるCoqプログラミング
よくわかるCoqプログラミングよくわかるCoqプログラミング
よくわかるCoqプログラミング
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話
 
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
 
AtCoder167Dをダブリングで解く
AtCoder167Dをダブリングで解くAtCoder167Dをダブリングで解く
AtCoder167Dをダブリングで解く
 
楕円曲線入門 トーラスと楕円曲線のつながり
楕円曲線入門トーラスと楕円曲線のつながり楕円曲線入門トーラスと楕円曲線のつながり
楕円曲線入門 トーラスと楕円曲線のつながり
 
[DL輪読会]Variational Autoencoder with Arbitrary Conditioning
[DL輪読会]Variational Autoencoder with Arbitrary Conditioning[DL輪読会]Variational Autoencoder with Arbitrary Conditioning
[DL輪読会]Variational Autoencoder with Arbitrary Conditioning
 
lispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep Learninglispmeetup#63 Common Lispでゼロから作るDeep Learning
lispmeetup#63 Common Lispでゼロから作るDeep Learning
 
Rustで楽しむ競技プログラミング
Rustで楽しむ競技プログラミングRustで楽しむ競技プログラミング
Rustで楽しむ競技プログラミング
 
素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe 素数の分解法則(フロベニウスやばい) #math_cafe
素数の分解法則(フロベニウスやばい) #math_cafe
 
最大流 (max flow)
最大流 (max flow)最大流 (max flow)
最大流 (max flow)
 
競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略競技プログラミング頻出アルゴリズム攻略
競技プログラミング頻出アルゴリズム攻略
 
暗認本読書会12
暗認本読書会12暗認本読書会12
暗認本読書会12
 
AtCoder Beginner Contest 008 解説
AtCoder Beginner Contest 008 解説AtCoder Beginner Contest 008 解説
AtCoder Beginner Contest 008 解説
 
キムワイプなスライド作った
キムワイプなスライド作ったキムワイプなスライド作った
キムワイプなスライド作った
 
実用Brainf*ckプログラミング
実用Brainf*ckプログラミング実用Brainf*ckプログラミング
実用Brainf*ckプログラミング
 
Rust、何もわからない...#7 VecDeque再訪
Rust、何もわからない...#7 VecDeque再訪Rust、何もわからない...#7 VecDeque再訪
Rust、何もわからない...#7 VecDeque再訪
 
プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造プログラミングコンテストでのデータ構造
プログラミングコンテストでのデータ構造
 
動的計画法を極める!
動的計画法を極める!動的計画法を極める!
動的計画法を極める!
 
動的計画法
動的計画法動的計画法
動的計画法
 
abc032
abc032abc032
abc032
 

Andere mochten auch

Andere mochten auch (20)

Rubyの拡張をCrystalで書いてみる
Rubyの拡張をCrystalで書いてみるRubyの拡張をCrystalで書いてみる
Rubyの拡張をCrystalで書いてみる
 
Opal - Ruby Style!! Ruby in the browser
Opal - Ruby Style!!  Ruby in the browserOpal - Ruby Style!!  Ruby in the browser
Opal - Ruby Style!! Ruby in the browser
 
Global Education and Skills Forum 2017 - Educating Global Citizens
Global Education and Skills Forum  2017 -  Educating Global CitizensGlobal Education and Skills Forum  2017 -  Educating Global Citizens
Global Education and Skills Forum 2017 - Educating Global Citizens
 
Comparative genomics to the rescue: How complete is your plant genome sequence?
Comparative genomics to the rescue: How complete is your plant genome sequence?Comparative genomics to the rescue: How complete is your plant genome sequence?
Comparative genomics to the rescue: How complete is your plant genome sequence?
 
The use of blogs in teaching and learning literature in FL
The use of blogs in teaching and learning literature in FLThe use of blogs in teaching and learning literature in FL
The use of blogs in teaching and learning literature in FL
 
Mediación escolar e implantación de un plan de mediación en un centro educativo
Mediación escolar e implantación de un plan de mediación en un centro educativoMediación escolar e implantación de un plan de mediación en un centro educativo
Mediación escolar e implantación de un plan de mediación en un centro educativo
 
Lluvias en el norte 24.03.17
Lluvias en el norte 24.03.17Lluvias en el norte 24.03.17
Lluvias en el norte 24.03.17
 
kintone Café Akita Vol.1 対面開発
kintone Café Akita Vol.1 対面開発kintone Café Akita Vol.1 対面開発
kintone Café Akita Vol.1 対面開発
 
Gender gap in public speaking
Gender gap in public speakingGender gap in public speaking
Gender gap in public speaking
 
パケットが教えてくれた ルートサーバが 13個の理由
パケットが教えてくれた ルートサーバが 13個の理由パケットが教えてくれた ルートサーバが 13個の理由
パケットが教えてくれた ルートサーバが 13個の理由
 
Emergencias oncológicas (Diplomado UniRemington) Parte 4/6
Emergencias oncológicas (Diplomado UniRemington) Parte 4/6Emergencias oncológicas (Diplomado UniRemington) Parte 4/6
Emergencias oncológicas (Diplomado UniRemington) Parte 4/6
 
Quimioterapia paliativa (Diplomado UniRemington) Parte 5c/6
Quimioterapia paliativa (Diplomado UniRemington) Parte 5c/6Quimioterapia paliativa (Diplomado UniRemington) Parte 5c/6
Quimioterapia paliativa (Diplomado UniRemington) Parte 5c/6
 
RUNNING Smalltalk - 実践Smalltalk
RUNNING Smalltalk - 実践SmalltalkRUNNING Smalltalk - 実践Smalltalk
RUNNING Smalltalk - 実践Smalltalk
 
Open Source Insight: CVE-2017-2636 Vuln of the Week & UK National Cyber Secur...
Open Source Insight: CVE-2017-2636 Vuln of the Week & UK National Cyber Secur...Open Source Insight: CVE-2017-2636 Vuln of the Week & UK National Cyber Secur...
Open Source Insight: CVE-2017-2636 Vuln of the Week & UK National Cyber Secur...
 
Peter Allor - The New Era of Cognitive Security
Peter Allor - The New Era of Cognitive SecurityPeter Allor - The New Era of Cognitive Security
Peter Allor - The New Era of Cognitive Security
 
Spiders, Chatbots, and the Future of Metadata: A look inside the BNC BiblioSh...
Spiders, Chatbots, and the Future of Metadata: A look inside the BNC BiblioSh...Spiders, Chatbots, and the Future of Metadata: A look inside the BNC BiblioSh...
Spiders, Chatbots, and the Future of Metadata: A look inside the BNC BiblioSh...
 
Conference entreprise libérée
Conference entreprise libéréeConference entreprise libérée
Conference entreprise libérée
 
はじめてのgithub
はじめてのgithubはじめてのgithub
はじめてのgithub
 
Ten query tuning techniques every SQL Server programmer should know
Ten query tuning techniques every SQL Server programmer should knowTen query tuning techniques every SQL Server programmer should know
Ten query tuning techniques every SQL Server programmer should know
 
Designing for Diversity in Design Orgs (Presentation)
Designing for Diversity in Design Orgs (Presentation)Designing for Diversity in Design Orgs (Presentation)
Designing for Diversity in Design Orgs (Presentation)
 

Ähnlich wie How to write Ruby extensions with Crystal

A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
旻琦 潘
 
Lightening Talk: Model Cat Can Haz Scope?
Lightening Talk: Model Cat Can Haz Scope?Lightening Talk: Model Cat Can Haz Scope?
Lightening Talk: Model Cat Can Haz Scope?
evenellie
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
Jano Suchal
 
C Sharp: Basic to Intermediate Part 01
C Sharp: Basic to Intermediate Part 01C Sharp: Basic to Intermediate Part 01
C Sharp: Basic to Intermediate Part 01
Zafor Iqbal
 

Ähnlich wie How to write Ruby extensions with Crystal (20)

Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012Ruby C extensions at the Ruby drink-up of Sophia, April 2012
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
 
Ruby Internals
Ruby InternalsRuby Internals
Ruby Internals
 
06 ruby variables
06 ruby variables06 ruby variables
06 ruby variables
 
iOS Session-2
iOS Session-2iOS Session-2
iOS Session-2
 
05 ruby classes
05 ruby classes05 ruby classes
05 ruby classes
 
Ruby/Rails
Ruby/RailsRuby/Rails
Ruby/Rails
 
Ruby training day1
Ruby training day1Ruby training day1
Ruby training day1
 
Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.
 
Attributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active recordAttributes Unwrapped: Lessons under the surface of active record
Attributes Unwrapped: Lessons under the surface of active record
 
A tour on ruby and friends
A tour on ruby and friendsA tour on ruby and friends
A tour on ruby and friends
 
Ruby: Beyond the Basics
Ruby: Beyond the BasicsRuby: Beyond the Basics
Ruby: Beyond the Basics
 
Introduction to the Ruby Object Model
Introduction to the Ruby Object ModelIntroduction to the Ruby Object Model
Introduction to the Ruby Object Model
 
Oops concepts in php
Oops concepts in phpOops concepts in php
Oops concepts in php
 
Iq rails
Iq railsIq rails
Iq rails
 
Lightening Talk: Model Cat Can Haz Scope?
Lightening Talk: Model Cat Can Haz Scope?Lightening Talk: Model Cat Can Haz Scope?
Lightening Talk: Model Cat Can Haz Scope?
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
 
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyTDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
 
JavaScript(Es5) Interview Questions & Answers
JavaScript(Es5)  Interview Questions & AnswersJavaScript(Es5)  Interview Questions & Answers
JavaScript(Es5) Interview Questions & Answers
 
Cocoa for Web Developers
Cocoa for Web DevelopersCocoa for Web Developers
Cocoa for Web Developers
 
C Sharp: Basic to Intermediate Part 01
C Sharp: Basic to Intermediate Part 01C Sharp: Basic to Intermediate Part 01
C Sharp: Basic to Intermediate Part 01
 

Kürzlich hochgeladen

一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
pxcywzqs
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
JOHNBEBONYAP1
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
gajnagarg
 
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi EscortsRussian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Monica Sydney
 
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
ayvbos
 
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girlsRussian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
Monica Sydney
 
PowerDirector Explination Process...pptx
PowerDirector Explination Process...pptxPowerDirector Explination Process...pptx
PowerDirector Explination Process...pptx
galaxypingy
 
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
ydyuyu
 
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
ayvbos
 

Kürzlich hochgeladen (20)

APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53APNIC Updates presented by Paul Wilson at ARIN 53
APNIC Updates presented by Paul Wilson at ARIN 53
 
Microsoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck MicrosoftMicrosoft Azure Arc Customer Deck Microsoft
Microsoft Azure Arc Customer Deck Microsoft
 
Best SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency DallasBest SEO Services Company in Dallas | Best SEO Agency Dallas
Best SEO Services Company in Dallas | Best SEO Agency Dallas
 
一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
一比一原版(Offer)康考迪亚大学毕业证学位证靠谱定制
 
Trump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts SweatshirtTrump Diapers Over Dems t shirts Sweatshirt
Trump Diapers Over Dems t shirts Sweatshirt
 
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime NagercoilNagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
Nagercoil Escorts Service Girl ^ 9332606886, WhatsApp Anytime Nagercoil
 
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdfpdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
pdfcoffee.com_business-ethics-q3m7-pdf-free.pdf
 
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
Top profile Call Girls In Dindigul [ 7014168258 ] Call Me For Genuine Models ...
 
20240510 QFM016 Irresponsible AI Reading List April 2024.pdf
20240510 QFM016 Irresponsible AI Reading List April 2024.pdf20240510 QFM016 Irresponsible AI Reading List April 2024.pdf
20240510 QFM016 Irresponsible AI Reading List April 2024.pdf
 
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac RoomVip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
Vip Firozabad Phone 8250092165 Escorts Service At 6k To 30k Along With Ac Room
 
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
APNIC Policy Roundup, presented by Sunny Chendi at the 5th ICANN APAC-TWNIC E...
 
20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdf20240508 QFM014 Elixir Reading List April 2024.pdf
20240508 QFM014 Elixir Reading List April 2024.pdf
 
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
20240509 QFM015 Engineering Leadership Reading List April 2024.pdf
 
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi EscortsRussian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
Russian Escort Abu Dhabi 0503464457 Abu DHabi Escorts
 
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
一比一原版(Curtin毕业证书)科廷大学毕业证原件一模一样
 
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girlsRussian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
Russian Call girls in Abu Dhabi 0508644382 Abu Dhabi Call girls
 
Meaning of On page SEO & its process in detail.
Meaning of On page SEO & its process in detail.Meaning of On page SEO & its process in detail.
Meaning of On page SEO & its process in detail.
 
PowerDirector Explination Process...pptx
PowerDirector Explination Process...pptxPowerDirector Explination Process...pptx
PowerDirector Explination Process...pptx
 
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
哪里办理美国迈阿密大学毕业证(本硕)umiami在读证明存档可查
 
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
一比一原版(Flinders毕业证书)弗林德斯大学毕业证原件一模一样
 

How to write Ruby extensions with Crystal

  • 1. How to write Ruby extensions with Crystal @gaar4ica
 Anna Shcherbinina
  • 3. 5 YO, a lot of stuff
  • 4. So, I like Ruby
  • 5. But, sometimes, I need my code to work faster
  • 6. def fibonacci(n) n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2) end Case of possible bottle neck
  • 7. Ruby has C bindings
  • 8. C is hard to learn and understand Static types Allocating 
 memory And tons of other complications for Ruby developer
  • 9. I’m ruby developer, I don’t want to write my code in C
  • 10. I’m ruby developer, I want to write my code in Ruby. But to be honest… Node.js NET OWL PDF XML Redis C++ Scala BASIC C#
  • 11. I’m ruby developer, I want to write my code in Ruby
  • 12. Also, I like Crystal
  • 14. Guess the language # define class Dog class Dog def initialize(breed, name) @breed = breed @name = name end def bark puts 'Ruff! Ruff!' end def display puts "I am of #{@breed} breed and my name is #{@name}" end end
 # make an object d = Dog.new('Labrador', 'Benzy')
  • 15. Crystal compiles to native code Spoiler about crystal
  • 16. So, I like Crystal
  • 17.
  • 21. C layer Link Crystal classes and methods to Ruby, so Ruby knows about them Translate 
 Ruby-types 
 to Crystal-types
  • 23. WUT? Compile to efficient 
 native code Statically 
 type-checked Ruby-inspired 
 syntax C bindings
  • 24. Web Frameworks • amatista • amethyst • kemal • moonshine Testing Search CacheDBDDBD Third-party 
 APIs Libs
  • 25. Ready for production or not? Web apps Microservice • maths calculation • small but heavy parts of projects What for
  • 26. Not so like ruby
  • 27. if @a # here @a can be nil end if @a.is_a?(String) # here @a is not guaranteed to be a String end if @a.responds_to?(:abs) # here @a is not guaranteed to respond to `abs` end The below doesn’t work with instance variables, class variables or global variables. Variables Not so like ruby
  • 28. To work with these, first assign them to a variable: if a = @a # here a can't be nil end # Second option: use `Object#try` found in the standard library @a.try do |a| # here a can't be nil end if (a = @a).is_a?(String) # here a is guaranteed to be a String end Variables Not so like ruby
  • 29. Classes and methods Not so like ruby Overloading Return types Visibility Finalize
  • 30. Macros Not so like ruby class Object macro def instance_vars_names : Array(String) {{ @type.instance_vars.map &.name.stringify }} end end class Person def initialize(@name, @age) end end person = Person.new "John", 30 person.instance_vars_names #=> ["name", "age"]
  • 31. Threads Not so like ruby def generate(chan) i = 2 loop do chan.send(i) i += 1 end end def filter(in_chan, out_chan, prime) loop do i = in_chan.receive if i % prime != 0 out_chan.send(i) end end end ch = Channel(Int32).new spawn generate(ch) 100.times do prime = ch.receive puts prime ch1 = Channel(Int32).new spawn filter(ch, ch1, prime) ch = ch1 end
  • 32. Benchmarking Time (s) Go Erlang Crystal Scala Ruby C Crystal Ruby C Crystal Ruby 4.084.082.21 27.92 6.025.08 41.73 6.426.091.971.48 Memory (Mb) Go Erlang Crystal Scala Ruby C Crystal Ruby C Crystal Ruby 162.40 1.400.40 115.50107.60 32.4030.00 1.505.3017.10 2.00 Threadring Binarytree Fast Threadring Binarytree Fast
  • 33. Back to case of possible bottle neck def fibonacci(n) n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2) end
  • 35. Less work for C Passing primitive data structures: • integer • string • boolean • float / decimal • etc. No allocation memory for complex data types Don’t do a lot of work for casting variables passed as attributes
  • 36. Ruby C API Entry point Then every C extension has to implement a function named Init_xxxxx (xxxxx being your extension’s name). It is being executed during the “require” of your extension. void Init_xxxxx() { // Code executed during "require" }
  • 37. Ruby C API Types Ruby C API defines a bunch of handful C constants defining standard Ruby objects: C Ruby Qnil nil Qtrue TRUE Qfalse FALSE rb_cObject Object rb_mKernel Kernel rb_cString String
  • 38. Ruby C API Declaring modules and classes // Creating classes // rb_define_class creates a new class named name // and inheriting from super. // The return value is a handle to the new class. VALUE rb_define_class(const char *name, VALUE super); // Creating modules // rb_define_module defines a module whose name // is the string name. // The return value is a handle to the module. VALUE rb_define_module(const char *name);
  • 39. Ruby C API Declaring methods // Creating a method // rb_define_method defines a new instance method in the class // or moduleklass. // The method calls func with argc arguments. // They differ in how they specify the name - rb_define_method // uses the constant string name void rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc); // rb_define_protected_method and rb_define_private_method are similar to rb_define_method, // except that they define protected and private methods, respectively. void rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc); void rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc);
  • 40. Ruby C API Ruby objects → C types // Convert Numeric to integer. long rb_num2int(VALUE obj); // Convert Numeric to unsigned integer. unsigned long rb_num2uint(VALUE obj); // Convert Numeric to double. double rb_num2dbl(VALUE); // Convert Ruby string to a String. VALUE rb_str_to_str(VALUE object); char* rb_string_value_cstr(volatile VALUE* object_variable);
  • 41. Ruby C API C types → Ruby objects // Convert an integer to Fixnum or Bignum. INT2NUM( int ); // convert an unsigned integer to Fixnum or Bignum. UINT2NUM( unsigned int ); // Convert a double to Float. rb_float_new( double ); // Convert a character string to String. rb_str_new2( char* ); // Convert a character string to ID (for Ruby function names, etc.). rb_intern( char* ); // Convert a character string to a ruby Symbol object. ID2SYM( rb_intern(char*) );
  • 42. Ruby C API Simple example # my_class.rb class MyClass def my_method(param1, param2) end end // my_class_ext.c static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE rb_param2) { // Code executed when calling my_method on an object of class MyClass } void Init_xxxxx() { // Define a new class (inheriting Object) in this module VALUE myclass = rb_define_class("MyClass", rb_cObject); // Define a method in this class, taking 2 arguments, // and using the C method "myclass_method" as its body rb_define_method(myclass, "my_method", myclass_mymethod, 2); }
  • 43. Ruby C API Simple example # my_class.rb class MyClass def my_method(param1, param2) end end // my_class_ext.c static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE rb_param2) { // Code executed when calling my_method on an object of class MyClass } void Init_xxxxx() { // Define a new class (inheriting Object) in this module VALUE myclass = rb_define_class("MyClass", rb_cObject); // Define a method in this class, taking 2 arguments, // and using the C method "myclass_method" as its body rb_define_method(myclass, "my_method", myclass_mymethod, 2); }
  • 44. Ruby C API Simple example # my_class.rb class MyClass def my_method(param1, param2) end end // my_class_ext.c static VALUE myclass_mymethod(VALUE rb_self, VALUE rb_param1, VALUE rb_param2) { // Code executed when calling my_method on an object of class MyClass } void Init_xxxxx() { // Define a new class (inheriting Object) in this module VALUE myclass = rb_define_class("MyClass", rb_cObject); // Define a method in this class, taking 2 arguments, // and using the C method "myclass_method" as its body rb_define_method(myclass, "my_method", myclass_mymethod, 2); }
  • 45. def fibonacci(n) n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2) end Back to case of possible 
 bottle neck And solution C
  • 46. A lib declaration groups C functions and types that belong to 
 a library. Crystal extension It’s easy lib CrRuby type VALUE = Void* $rb_cObject : VALUE end
  • 47. Every ruby object is treated as type VALUE in C. Crystal extension It’s easy lib CrRuby type VALUE = Void* $rb_cObject : VALUE end
  • 48. rb_cObject is a C constant defining standard Ruby Object class. Crystal extension It’s easy lib CrRuby type VALUE = Void* $rb_cObject : VALUE end
  • 49. lib CrRuby type VALUE = Void* $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE end A fun declaration inside a lib binds to a C function. We bind rb_num2int & rb_int2inum, to use it later. Crystal extension It’s easy
  • 50. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end Crystal extension It’s easy We bind rb_define_class & rb_define_method.
  • 51. def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end Our new and shiny fibonacci method in Crystal. def fibonacci(n) n <= 1 ? n : fibonacci(n - 1) + fibonacci(n - 2) end Do you see the difference with implementation in Ruby? Crystal extension It’s easy
  • 52. Crystal extension It’s easy Let’s create a wrapper for this method, used for: • convert inbound Ruby-type parameter to Crystal; • convert outbound result back to Ruby type. def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end
  • 53. Crystal extension It’s easy Now we are done with our functions and C bindings. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end
  • 54. Crystal extension It’s easy Now we are done with our functions and C bindings. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end
  • 55. Crystal extension It’s easy Now we are done with our functions and C bindings. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end
  • 56. Crystal extension It’s easy Now we are done with our functions and C bindings. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end
  • 57. Crystal extension It’s easy We bind init function, the first one to be called. As you remember, a function named Init_xxxxx is being executed during the “require” of your extension. fun init = Init_cr_math end
  • 58. Crystal extension It’s easy Firstly, we start garbage collector. We need to invoke Crystal's "main" function, the one that initializes all constants and runs the top-level code. We pass 0 and null to argc and argv. fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) end
  • 59. Crystal extension It’s easy We define class CrMath. fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject) CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1) end
  • 60. Crystal extension It’s easy We define class CrMath. Attach method fibonacci to class. fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject) CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1) end
  • 61. Crystal extension Ready to compile We have Crystal library with C bindings. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject) CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1) end
  • 62. Crystal extension Ready to compile We have method fibonacci_cr and wrapper for it. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject) CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1) end
  • 63. Crystal extension Ready to compile We have entry point. lib CrRuby type VALUE = Void* type METHOD_FUNC = VALUE, VALUE -> VALUE $rb_cObject : VALUE fun rb_num2int(value : VALUE) : Int32 fun rb_int2inum(value : Int32) : VALUE fun rb_define_class(name: UInt8*, super: VALUE) : VALUE fun rb_define_method(klass: VALUE, name: UInt8*, func: METHOD_FUNC, argc: Int32) end def fibonacci_cr_wrapper(self : CrRuby::VALUE, value : CrRuby::VALUE) int_value = CrRuby.rb_num2int(value) CrRuby.rb_int2inum(fibonacci_cr(int_value)) end def fibonacci_cr(n) n <= 1 ? n : fibonacci_cr(n - 1) + fibonacci_cr(n - 2) end fun init = Init_cr_math GC.init LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null) cr_math = CrRuby.rb_define_class("CrMath", CrRuby.rb_cObject) CrRuby.rb_define_method(cr_math, "fibonacci", ->fibonacci_cr_wrapper, 1) end
  • 64. Crystal extension Ready to compile Makefile CRYSTAL = crystal UNAME = "$(shell uname -ms)" LIBRARY_PATH = $(shell brew --prefix crystal-lang)/embedded/lib TARGET = cr_math.bundle $(TARGET): cr_math.o $(CC) -bundle -L$(LIBRARY_PATH) -o $@ $^ cr_math.o: cr_math.cr $(CRYSTAL) build --cross-compile $(UNAME) $<
  • 65. $ irb 2.1.6 :001 > require './cr_math' => true 2.1.6 :002 > CrMath.new.fibonacci(20) => 6765 Crystal extension Using in Ruby
  • 66. # benchmark.rb require 'benchmark' require './cr_math' # We have compiled cr_math.bundle require './rb_math' iterations = 10_000 number = 20 Benchmark.bm do |bm| bm.report("rb") do iterations.times { RbMath.new.fibonacci(number) } end bm.report("cr") do iterations.times { CrMath.new.fibonacci(number) } end end # rb_math.rb class RbMath def fibonacci(n) return n if n <= 1 fibonacci(n - 1) + fibonacci(n - 2) end end Crystal extension Benchmarking
  • 67. # benchmark.rb require 'benchmark' require './cr_math' # We have compiled cr_math.bundle require './rb_math' iterations = 10_000 number = 20 Benchmark.bm do |bm| bm.report("rb") do iterations.times { RbMath.new.fibonacci(number) } end bm.report("cr") do iterations.times { CrMath.new.fibonacci(number) } end end # rb_math.rb class RbMath def fibonacci(n) return n if n <= 1 fibonacci(n - 1) + fibonacci(n - 2) end end Crystal extension Benchmarking
  • 68. $ ruby benchmark.rb user system total real rb 10.270000 0.030000 10.300000 ( 10.314595) cr 0.460000 0.000000 0.460000 ( 0.464087) Crystal extension Benchmarking Ta-Da!