Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Native Extensions Served 3 Ways
Search
Tejas Dinkar
January 03, 2014
Technology
390
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Native Extensions Served 3 Ways
This talk was given at Garden City Ruby Conf 2014
Tejas Dinkar
January 03, 2014
More Decks by Tejas Dinkar
See All by Tejas Dinkar
Quick Wins for Page Speed
gja
0
160
Progressive Web Apps In Clojure(Script)
gja
4
2.5k
Monads you've already put in production (without knowing it)
gja
1
1.2k
Lightning - Monads you already use (without knowing it)
gja
1
430
Other Decks in Technology
See All in Technology
GitHub Copilot 最新アップデート – 「一歩先」の実践活用術
moulongzhang
5
1.7k
When Platform Engineering Meets GenAI
sucitw
0
170
BPaaSで進むAIオペレーションの現在地 AI実装が効く領域とスケーラビリティの選定と実装
kentarofujii
0
150
自分が詳しくない領域でAIを使う #プロヒス2026
konifar
20
7.4k
SteampipeとExcel Power QueryでAWS構成定義書の作成を自動化する
jhashimoto
0
180
OTel × Datadog で 「AI活用」を計測し、改善に繋げる
shihochan
2
630
フルAIで個人開発して学んだあれこれ / yuruai vol.1
isaoshimizu
0
110
Comment regagner la souveraineté de vos données tout en étant payé grâce à Nostr !
rlifchitz
0
190
【セミナー資料】Claude Code をセキュアに使うための考え方と設定の勘どころ / Claude Code Webinar 20260616
masahirokawahara
2
460
事業会社における 機械学習・推薦システム技術の活用事例と必要な能力 / ml-recsys-in-layerx-wantedly-2026
yuya4
0
160
FPGAの開発コンペでZephyrを使ってみた
iotengineer22
0
190
起点・思考・出力で分解する 〜PM業務の自動化設計〜
kazu_kichi_67
1
1k
Featured
See All Featured
BBQ
matthewcrist
89
10k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Building the Perfect Custom Keyboard
takai
2
800
Building Flexible Design Systems
yeseniaperezcruz
330
40k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
How to Think Like a Performance Engineer
csswizardry
28
2.7k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
580
We Have a Design System, Now What?
morganepeng
55
8.2k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
210
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Transcript
Native Extensions Served 3 Ways Tejas Dinkar Nilenso Software
about.me • Hi, I’m Tejas • Nilenso: Partner • twitter:
tdinkar • github: gja
about.talk • Expect to see lots of code • Will
have about 5 minutes for questions • Please laugh at my jokes! • Will cover C Extensions, FFI and SWIG
Native Extensions • Integrate with new libraries • Improve Performance
of critical code • Write code that works across languages • Feel super 1337
Let’s talk about Python • Pythonista’s in the house? •
Yes, I’m trolling you! http://montgomeryq.blogspot.in/2011/05/random-illustration-tuesday-python-ruby.html
None
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
#include "Python.h" #include "ruby.h" ! static PyObject *python_ruby_eval(PyObject *self, PyObject
*string) { VALUE val = rb_eval_string(PyString_AsString(string)); switch(TYPE(val)) { case T_FIXNUM: return PyInt_FromLong(FIX2INT(val)); case T_STRING: return PyString_FromString(StringValuePtr(val)); default: return Py_None; // Can handle these cases later } } ! static PyMethodDef module_functions[] = { { "eval", python_ruby_eval, METH_O, "Evaluate Ruby Code" }, { NULL } }; ! void initruby(void) { ruby_init(); Py_InitModule3("ruby", module_functions, "A ruby module for python."); }
Require Files? static PyObject *python_ruby_require(PyObject *self, PyObject *file) { rb_require(PyString_AsString(file));
return Py_True; }
Congrats!
Common Fears MEMORY ALLOCATION!?
Memory Management • Data_Wrap_Struct(klass, mark_cb, free_cb, *data) • Data_Get_Struct( VALUE,
data_type, data* )
Common Fears
Portability http://geekandpoke.typepad.com/geekandpoke/2008/05/the-history-of.html
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE self, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE str2, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
void Init_String(void) {! rb_cString = rb_define_class("String", rb_cObject);! // ...! rb_define_method(rb_cString,
"eql?", rb_str_eql, 1);! rb_define_method(rb_cString, "==", rb_str_equal, 1);! // ...! rb_define_method(rb_cString, "insert", rb_str_insert, 2);! rb_define_method(rb_cString, "length", rb_str_length, 0);! // ...! }! ! static VALUE rb_str_eql(VALUE str2, VALUE str2)! {! if (self == str2) return Qtrue;! if (!RB_TYPE_P(str2, T_STRING)) return Qfalse;! return str_eql(self, str2);! }! string.c
C Extensions Native Code Ruby Code Ruby Aware! Native Code
Foreign Function Interface Native Code Ruby Code Native Aware! Ruby
Code
Foreign Function Interface • A Ruby DSL • Works across
all Ruby Implementations • Converts to and from C primitives for you
example require 'ffi'! ! module MyLib! extend FFI::Library! ffi_lib 'c'!
attach_function :puts, [:string], :int! end! ! MyLib.puts 'Hello, World using libc!'
another example require 'ffi'! ! module MyMathLib! extend FFI::Library! ffi_lib
'm'! attach_function :pow, [:double, :double],! :double! end! ! MyMathLib.pow(4, 5) # => 1024.0
Lots of built in types Numbers!! ! ! ! !
Character!! ! ! ! ! Other! :int! ! ! ! ! ! ! :char!! ! ! ! ! ! ! :pointer! :short! ! ! ! ! ! :string! :long! :double! :float!
Foreign Function Interface • Probably your best solution • It’s
really easy • Do your modelling in Ruby • Still have to worry about GC • Sadly, no C++ without wrapping
Memory in FFI def run_query_which_will_crash! db_connection = MyFFIModule.database_connection("localhost")! MyFFIModule.database_query(db_connection, "select
* from users")! end!
Memory in FFI def run_query_which_will_crash! db_connection = MyFFIModule.database_connection("localhost")! MyFFIModule.database_query(db_connection, "select
* from users")! end! This will get GCed
SWIG • Simplified Wrapper and Interface Generator • Annotate your
C/C++ header files • It generates native extensions for languages • About 20 languages currently supported
SWIG Native Code Ruby Code Magic Python Code
The Magic • Takes an interface file • Auto generates
code to make it work • For ruby, it’s a `regular’ C extension • For python, it’s a a .c and .py file • For Java it’s a JNI interface • Still need to do your own GC
The Rectangle class Rectangle! {! int length;! int breadth;! !
public:! Rectangle(int length, int breadth);! int area();! };
The Rectangle class Rectangle! {! int length;! int breadth;! !
public:! Rectangle(int length, int breadth);! int area();! }; #ifdef SWIG %module shape %{ %} SWIG Stuff Here
require 'shapes'! ! rectangle = shapes.Rectangle.new(10, 12)! rectangle.area == 120!
Other Options • DL (Dynamic Load) • Fiddle(r)
TL;DR • Native Extensions are fun and easy to build
• The three big tools • You want to pick FFI if you don’t maintain the lib • SWIG may be better if you are a maintainer
Thank You Many Questions? wow so native so extension wow
no python such easy such performance super integration ruby = win