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
380
0
Share
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
150
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
420
Other Decks in Technology
See All in Technology
Introduction to Bill One Development Engineer
sansan33
PRO
0
410
AI バイブコーティングでキーボード不要?!
samakada
0
560
みんなの「データ活用」を支えるストレージ担当から持ち込むAWS活用/コミュニティー設計TIPS 10選~「作れる」より、「続けられる」設計へ~
yoshiki0705
0
250
Do Ruby::Box dream of Modular Monolith?
joker1007
1
340
Digitization部 紹介資料
sansan33
PRO
1
7.3k
Do Vibe Coding ao LLM em Produção para Busca Agêntica - TDC 2026 - Summit IA - São Paulo
jpbonson
3
110
AI時代のガードレールとしてのAPIガバナンス
nagix
0
280
こんなアーキテクチャ図はいやだ / Anti-pattern in AWS Architecture Diagrams
naospon
1
450
生成AIが変える SaaS の競争原理と弁護士ドットコムのプロダクト戦略
bengo4com
0
110
マルチエージェント × ハーネスエンジニアリング × GitLab Duo Agent Platformで実現する「AIエージェントに仕事をさせる時代へ。」 / 20260421 GitLab Duo Agent Platform
n11sh1
0
150
2026年、知っておくべき最新 サーバレスTips10選/serverless-10-tips
slsops
13
5.2k
昔はシンプルだった_AmazonS3
kawaji_scratch
0
330
Featured
See All Featured
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Building AI with AI
inesmontani
PRO
1
900
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.4k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.7k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
210
Measuring & Analyzing Core Web Vitals
bluesmoon
9
810
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
110k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.2k
Navigating Weather and Climate Data
rabernat
0
170
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
100
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
170
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