Improve extension API

: subtitle

C++ as better language for extension

: author

Kouhei Sutou

: institution

ClearCode Inc.

: content-source

RubyKaigi 2017

: date

2017-09-19

: allotted-time

35m

: theme

.

Ad1: I'm distributing shocker combatmen to Rabbit usersn(('tag:x-small:宣伝1:Rabbitユーザーに'))n(('tag:x-small:ショッカー戦闘員を配布中'))

# img
# src = images/shocker.jpeg
# relative_height = 110
# reflect_ratio = 0.1
# relative_margin_top = -2

Slide properties

: enable-title-on-image

true

Ad2: Silver sponsor

# img
# src = images/clear-code-silver-sponsor.png
# relative_height = 100
# reflect_ratio = 0.1

Slide properties

: enable-title-on-image

false

Ad3: Red Data Tools

* Project that provides data processing tools for Ruby\n
  (('note:Ruby用のデータ処理ツール群を提供するプロジェクト'))
  * https://red-data-tools.github.io/
* Workshop during the afternoon break on the 2nd day (today!)\n
  (('note:2日目(今日!)の午後休憩中にワークショップがあるよ!'))

Ad4: OSS Gate

* Project that increases people who join OSS development\n
  (('note:OSSの開発に継続的に参加する人を継続的に増やす取り組み'))
  * https://oss-gate.github.io/

Ad4: OSS Gate

* Ruby is OSS\n
  (('note:RubyもOSS'))
  * OSS Gate wants to increase people to join Ruby itself and RubyGems development!\n
    (('note:OSS GateではRuby本体の開発や各種RubyGemの開発に参加する人も増やしたい!'))

Ad4: OSS Gate

* Now, in Tokyo, Sapporo, Osaka and Kyoto\n
  (('note:現在は東京・札幌・大阪・京都で活動中'))
  * If you live near by, join "OSS Gate workshop"!\n
    (('note:これらの地域に住んでいる人は「OSS Gateワークショップ」に参加しよう!'))

Ad4: OSS Gate

* Want to expand to Hiroshima and other areas all over the world!\n
  (('note:広島や世界中のいろんな地域で活動したい!'))
  * If you're interested in increasing people who join OSS development, talk to me!\n
    (('note:OSSの開発に参加する人が増えることに興味のある人は私に声をかけて!'))

What I want to don(('note:やりたいこと'))

(('tag:center')) Improve performancen with C/C++ librariesn (('note:C/C++のライブラリーを使った高速化'))

* Not create binding\n
  (('note:バインディングを作りたいわけじゃない'))

Point of improving perfn(('note:高速化するために大事なこと'))

(('tag:center')) Done in C/C++n as much as possiblen (('note:できるだけC/C++内で完結させる'))

* Don't move between\n
  C/C++ and Ruby\n
  (('note:C/C++とRuby間でいったりきたりしない'))

Example: sumn(('note:例:#sum'))

# coderay ruby

numbers = (1..100000).to_a
# Move between C and Ruby: 25.1ms
numbers.inject(&:+)
# Done in C:                0.5ms
# 50x faster(50倍速い)
numbers.sum

FYI: inject(symbol)n(('note:参考情報:#inject(symbol)'))

# coderay ruby

numbers = (1..100000).to_a
# Move between C and Ruby: 25.1ms
numbers.inject(&:+)
# Done in C:                0.5ms
# 50x faster(50倍速い)
numbers.inject(:+)

Extension and bindingn(('note:拡張ライブラリーとバインディング'))

* Extension(('note:(拡張ライブラリー)'))
  * Ruby library implemented in C\n
    (('note:Cで実装されたRubyのライブラリー'))
* Binding(('note:(バインディング)'))
  * Ruby library to use library implemented in other languages\n
    (('note:他言語実装のライブラリを使うためのRubyのライブラリ'))

Binding usagen(('note:バインディングの使い方'))

* Export each API to Ruby\n
  (('note:それぞれのAPIをRubyで使えるようにする'))
* Combine exported APIs in Ruby\n
  (('note:バインディングが提供するAPIをRubyレベルで組み合わせる'))

Binding usage examplen(('note:バインディングの使い方例'))

# coderay ruby

require "cairo"
include Cairo
# Combine APIs
s = PDFSurface.new("red.pdf", 10, 10) # API
context = Context.new(s)              # API
context.set_source_color(:red)        # API
context.paint                         # API
context.show_page                     # API
s.finish                              # API

Point of improving perfn(('note:高速化するために大事なこと'))

(('tag:center')) Done in C/C++n as much as possiblen (('note:できるだけC/C++内で完結させる'))

* Don't move between\n
  C/C++ and Ruby\n
  (('note:C/C++とRuby間でいったりきたりしない'))

Perf improvement examplen(('note:高速化例'))

# coderay ruby

# Don't combine APIs in Ruby
# RubyレベルでAPIを組み合わせない
## context.set_source_color(:red) # API
## context.paint                  # API
## context.show_page              # API
# Just call higher level API in Ruby
# Rubyからはもっと高レベルなAPIを呼び出す
context.show_red_page # Implemented in C
                      # ここはCで実装

What I want to don(('note:やりたいこと'))

(('tag:center')) Improve performancen with C/C++ librariesn (('note:C/C++のライブラリーを使った高速化'))

* Not create binding\n
  (('note:バインディングを作りたいわけじゃない'))

Use casen(('note:高速化したい場面'))

* Machine learning\n
  (('note:機械学習'))
  * Combine array/matrix operations\n
    (('note:配列・行列に対する演算をまとめる'))

Raw C API for extensionn(('note:拡張ライブラリー用の生のC API'))

(('tag:center')) Not bad but can be verbose because of Cn (('note:悪くないんだけどCなので冗長'))

* Need better approach\n
  (('note:もっといい感じの方法を使いたい'))

Requirementsn(('note:要件'))

* Easy to use C/C++ libraries\n
  (('note:C/C++のライブラリーを簡単に使えること'))
* Easy to write (('note:as much as possible'))\n
  (('note:できるだけ書きやすいこと'))
* Easy to debug (('note:as much as possible'))\n
  (('note:できるだけデバッグしやすいこと'))

Approaches(('note:(実現方法)'))

* Extend language to support writing extension\n
  (('note:拡張ライブラリーを書けるように言語を拡張'))
* Not based on C\n
  (('note:C以外の言語を使う'))
* Provide convenient API\n
  (('note:便利APIを提供'))

Recommended approachn(('note:オススメの実現方法'))

* Extend language to support writing extension\n
  (('note:拡張ライブラリーを書けるように言語を拡張'))
* Not based on C\n
  (('note:C以外の言語を使う'))
* ((*Provide convenient API*))\n
  (('note:便利APIを提供'))

Provide convenient APIn(('note:便利なAPIを提供'))

* Rice: ((*C++*)) + Ruby
* Ext++: ((*C++*))11 + Ruby
* Boost.Python: ((*C++*)) + Python
* pybind11: ((*C++*))11 + Python

Useful C++ propertiesn(('note:C++の便利の性質'))

* C++ can use C API directory\n
  (('note:C++ではCのAPIを直接使える'))
  * No wrapper API or libffi\n
    (('note:ラッパーAPIもlibffiもいらない'))
* C++((*11 or later*)) has many convenient features\n
  (('note:C++11以降には便利機能がたくさんある'))

C++ convenient feature1n(('note:C++の便利機能1'))

(('tag:center')) Type detection with “auto”n (('note:autoで型推論(C++11)'))

# coderay cpp

int n = 10;
auto square = n * n;
// square's type is "int"
// squareの型は「int」

C++ convenient feature2n(('note:C++の便利機能2'))

(('tag:center')) Lambda expression (C++11)n (('note:ラムダ式(C++11)'))

# coderay cpp

// In Ruby: ->(n) {n * n}
auto square = [](int n) {
  return n * n; // Return type is detected
};
square(10); // => 100

C++ convenient feature3n(('note:C++の便利機能3'))

(('tag:center')) Default argumentn (('note:デフォルト引数'))

# coderay cpp

// In Ruby: def square(n=10)
int square(int n=10) {
  return n * n;
}
// square() == square(10)

Convenient API example1n(('note:便利なAPI例1'))

# coderay ruby

# Ruby: Normal
class Sample
  def hello
    "Hello"
  end
end

Convenient API example1n(('note:便利なAPI例1'))

# coderay ruby

# Ruby: No syntax sugar
Sample = Class.new do
  define_method(:hello) do
    "Hello"
  end
end

Convenient API example1n(('note:便利なAPI例1'))

# coderay cpp

// C++: Ext++
#include <ruby.hpp>
extern "C" void Init_sample(void) {
  // Parent class (rb_cObject) is omittable
  rb::Class("Sample"). // class Sample in Ruby
    define_method("hello", // def hello in Ruby
      [](VALUE self) { // ->() {"Hello"} in Ruby
        return rb_str_new_static("Hello");
      });
}

Convenient API example1n(('note:便利なAPI例1'))

# coderay c

/* C */
#include <ruby.h>
static VALUE rb_sample_hello(VALUE self) {
  return rb_str_new_static("Hello");
} /* ↑Definition. */
void Init_sample(void) {
  /* ↓Must specify parent class. */
  VALUE sample = rb_define_class("Sample", rb_cObject);
  /* ↓Registration. They are separated. */
  rb_define_method(sample, "hello", rb_sample_hello, 0);
}

C++ convenient feature4n(('note:C++の便利機能4'))

(('tag:center')) Custom type conversionn (('note:型変換のカスタマイズ'))

* "Cast" is customizable\n
  (('note:「キャスト」をカスタマイズできるということ'))

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

// Wrapper class of VALUE
class Object {
public:
  // def initialize(rb_object)
  //   @rb_object_ = rb_object
  // end
  Object(VALUE rb_object) : rb_object_(rb_object) {}
private:
  VALUE rb_object_;
};

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

class Object {
  operator bool() const {
    return RTEST(rb_object_);
  }
};
// Object nil(Qnil); // Qnil wrapper
// if (nil) { → if (RTEST(Qnil)) {

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

// Trap1(罠1)
// bool→int cast is available
// Implicit Object→bool→ int cast
// bool→intのキャストができるので
// 暗黙的にObject→bool→intとキャスト
Object(Qture) + 1; // → RTEST(Qtrue) + 1
                   // → 1 + 1
                   // → 2

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

class Object {
  // Deny explicit cast (C++11)
  // 暗黙のキャストを禁止(C++11)
  explicit operator bool() const {
    return RTEST(rb_object_);
  }
};
// Object(Qtrue) + 1; // → Compile error

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

// Trap2(罠2)
class Object {
public:
  // Used as implicit VALUE→Object cast
  // 暗黙のVALUE→Objectキャストに使われる
  Object(VALUE rb_object);
};

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

// Trap2(罠2)
// VALUE is just a number(VALUEはただの数値)
typedef unsigned long VALUE;
Object identify(Object x) {return x;}
// Implicit VALUE→Object cast
// 暗黙的にVALUE→Objectとキャスト
identify(100); // == identify(Object(100));

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

class Object {
  // Deny explicit cast
  // 暗黙のキャストを禁止
  explicit Object(VALUE rb_object);
};
// identify(100); // → Compile error

Custom type conversionn(('note:型変換のカスタマイズ'))

# coderay cpp

class Object {
  operator VALUE() const {return rb_object_;}
};
// Convenient(便利)
rb_p(Object(Qnil)); // → rb_p(Qnil);
// Not compile error. Hmm...
Object(Qnil) + 1;   // → Qnil + 1;
                    // → 8 + 1;
                    // → 9;

C++ convenient feature5n(('note:C++の便利機能5'))

(('tag:center')) Template and specializationn (('note:テンプレートと特殊化'))

* 👍Consistent cast API\n
  (('note:一貫性のあるキャストAPIに使える'))

Consistent cast APIn(('note:一貫性のあるキャストAPI'))

# coderay cpp

namespace rb {
  // Consistent cast API
  // Example: rb::cast<int32_t>(Object(NUM2INT(10));
  // Example: rb::cast<Object>(10);
  // FYI: C++ cast syntax: static_cast<TYPE>(expression)
  template <typename RETURN_TYPE,
            typename ARGUMENT_TYPE>
  inline RETURN_TYPE cast(ARGUMENT_TYPE object);
}

Consistent cast APIn(('note:一貫性のあるキャストAPI'))

# coderay cpp

template <> // rb::cast<int32_t>(Object(NUM2INT(10));
inline int32_t cast<int32_t, Object>(Object rb_object) {
  return NUM2INT(rb_object);
}
template <> // rb::cast<Object>(10);
inline Object cast<Object, int32_t>(int32_t n) {
  return Object(INT2NUM(n));
}

Consistent cast APIn(('note:一貫性のあるキャストAPI'))

# coderay cpp

// rb::cast<const char *>(Object(rb_str_new_cstr("X"));
template <> inline
const char *cast<const char *, Object>(Object rb_object) {
  VALUE rb_object_raw = rb_object;
  return StringValueCStr(rb_object_raw);
}
template <> inline // rb::cast<Object>("hello");
Object cast<Object, const char *>(const char *c_string) {
  return Object(rb_str_new_cstr(c_string));
}

C++ convenient feature6n(('note:C++の便利機能6'))

(('tag:center')) Initializer list (C++11)n (('note:初期化リスト(C++11)'))

* "{A,B,...}" is customizable\n
  (('note:「{A, B, ...}」をカスタマイズできる'))

Initializer listn(('note:初期化リスト'))

# coderay cpp

Object Object::send(
  ID name_id,
  std::initializer_list<VALUE> args);
// Ruby: "hello".send(:tr, "e", "E")
Object(rb_str_new_cstr("hello")).
  send(rb_intern("tr"),
       {rb_str_new_cstr("e"),
        rb_str_new_cstr("E")});

Initializer listn(('note:初期化リスト'))

# coderay cpp

Object Object::send(
  ID name_id,
  std::initializer_list<VALUE> args,
  VALUE (*block)(VALUE data));
// Ruby: array.send(:collect) {true}
Object(array).
  send(rb_intern("collect"),
       {}, // Clear API than variable arguments
       [](VALUE data) {return Qtrue;});

Convenient API example2n(('note:便利なAPI例2'))

# coderay cpp

// C++: Ext++
rb::Object(rb_n).
  send("step",
       // Implicit Object→VALUE cast
       {rb::cast<rb::Object>(10)},
       [](VALUE i) {return rb_p(i)});
// n.step(10) {|i| p i}

Convenient API example3n(('note:便利なAPI例3'))

# coderay cpp

// C++: Rice
#include <rice/Class.hpp>
static const char * // Not VALUE! (Auto convert)
rb_sample_hello(Rice::Object self) {
  return "Hello";
}
extern "C" void Init_sample() {
  Rice::define_class("Sample").
    define_method("hello", &rb_sample_hello);
}

C++ based API: Pros1n(('note:C++ベースのAPI:長所1'))

(('tag:center')) Easier to write than Cn (('note:Cより書きやすい'))

* Require C++11 or later\n
  (('note:C++11以降なら'))

C++ based API: Pros2n(('note:C++ベースのAPI:長所2'))

(('tag:center')) Easy to use for C API usersn (('note:既存のC APIを使っている人なら使いやすい'))

* Use C directly incl macro\n
  (('note:マクロも含めてCの機能を直接使える'))
* Don't need to migrate to all convenient API at once\n
  (('note:一気に書き換えるのではなく徐々に移行できる'))

C++ based API: Pros3n(('note:C++ベースのAPI:長所3'))

(('tag:center')) Easy to debug for C API usersn (('note:既存のC APIを使っている人ならデバッグしやすい'))

* Can use GDB/LLDB directly\n
  (('note:GDB/LLDBを直接使える'))
  * GDB/LLDB have built-in C++ support\n
    (('note:GDB/LLDBは組み込みでC++をサポート'))

C++ based API: Pros4n(('note:C++ベースのAPI:長所4'))

(('tag:center')) Easy to optimizen (('note:最適化しやすい'))

* [Feature #13434] better method definition in C API\n
  (('note:Cのメソッド定義APIの改良'))

Better method definitionn(('note:メソッド定義の改良'))

* Metadata for optimization\n
  (('note:最適化のためにメタデータを付与'))
  * e.g.: Reduce memory allocations\n
    (('note:例:メモリーアロケーションを減らす'))
* Lazy method definition\n
  (('note:必要になるまでメソッド定義を遅らせる'))
  * e.g.: Reduce start-up time\n
    (('note:例:起動時間の高速化'))

Argument metadatan(('note:引数のメタデータ'))

# coderay ruby

class Hello
  # Default argument is just for
  # example. Other metadata will
  # be more useful for optimization.
  def hello(name, message="world")
  end
end

Argument metadatan(('note:引数のメタデータ'))

# coderay cpp

// C++: Rice
cHello.
  define_method(
    "hello",
    &hello,
    (Rice::Arg("name"), // ↓Default
     Rice::Arg("message")="world"));

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay ruby

class X
  def a; end # Not define yet
  def b; end # Not define yet
end
x = X.new
x.a # Define #a and #b

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay c

/* One of new C API ideas */
struct rb_method_entries entries[] = {
  "a", ...,
  "b", ...,
};
/* The definitions aren't defined at once. */
/* They are defined when the next method call. */
rb_define_method_with_table(rb_cX, entries);

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay c

// C++ implementation sample
{
  rb::Class("X").
    // Don't call rb_define_method() yet.
    define_method("a", ...).
    // Don't call rb_define_method() yet.
    define_method("b", ...);
  // Destructor is called.
  // Call rb_define_method_with_table()
  // in destructor.
}

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay c

// Ext++ implementation is just for test
rb::Class("X").
  // Call rb_define_method() immediately.
  define_method("a", ...).
  // Don't call rb_define_method() in
  // the following define_method()s.
  enable_lazy_define_method().
  // Don't call rb_define_method() yet.
  define_method("b", ...);

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay ruby

# Define only benchmark code in Ruby.
# Benchmark target code is in C++.
n = 10000
Bench = Class.new do
  n.times do |i|
    define_method("method#{i}") do
    end
  end
end

Lazy method definitionn(('note:遅延メソッド定義'))

# coderay ruby

# Call benchmark code in Ruby.
# Benchmark target code is in C++.
n = 10000
bench = Bench.new
n.times do |i|
  bench.__send__("method#{i}")
end

Lazy method definitionn(('note:遅延メソッド定義'))

# RT

Type, Define only, Called

Normal, 5ms, 5ms
Lazy,   1ms, 5ms

(('tag:center')) 5x faster when any methods aren't calledn (('note:メソッドが呼ばれなければ5倍速い'))

C++ based API: Cons1n(('note:C++ベースのAPI:短所1'))

(('tag:center')) C++ is difficultn (('note:C++は難しい'))

* e.g.: Template\n
  (('note:たとえばテンプレート'))
* Easy to write unreadable code\n
  (('note:簡単にリーダブルじゃないコードを書ける'))

C++ based API: Cons2n(('note:C++ベースのAPI:短所2'))

(('tag:center')) Slower buildn (('note:ビルドが遅い'))

* It may reduce try&error cycle\n
  (('note:試行錯誤しにくくなるかも'))

C++ based API: Problemn(('note:C++ベースのAPI:課題'))

(('tag:center')) Exceptionn (('note:例外'))

* Ruby exception breaks C++ RAII (destructor)\n(('note:(Resource Acquisition Is Initialization)'))\n
  (('note:Rubyの例外発生→C++のRAII(デストラクター)が動かない'))
  * Because it uses setjmp/longjmp\n
    (('note:Rubyの例外はsetjmp/longjmpを使っているから'))

Exception: Solutionn(('note:例外:解決法'))

(1) Rescue Ruby exception\n
    (('note:Rubyの例外をrescue'))
(2) Throw C++ exception\n
    (('note:C++の例外にしてthrow'))
(3) Re-raise the Ruby exception\n
    (('note:安全な場所でRubyの例外を再raise'))

Conclusionn(('note:まとめ'))

* C++ based API is useful\n
  (('note:C++ベースのAPIは便利'))
  * For writing ext uses C/C++ library\n
    (('note:C/C++のライブラリを使う拡張ライブラリを書くとき'))
  * For optimizing w/ easy to use API\n
    (('note:例:使いやすいAPIを維持したまま最適化するとき'))

Slide properties

: image-slide-number-last-slide

true

Appendixn(('note:付録'))

(('tag:center')) Introduce easy to write extension approachesn (('note:拡張ライブラリーを簡単に実装する方法を紹介'))

* The following contents are used only when time is remained\n
  (('note:以降の内容は時間が残っている場合だけ使う'))

Approaches(('note:(実現方法)'))

* Extend language to support writing extension\n
  (('note:拡張ライブラリーを書けるように言語を拡張'))
* Not based on C\n
  (('note:C以外の言語を使う'))
* Provide convenient API\n
  (('note:便利APIを提供'))

Extend languagen(('note:言語を拡張'))

* Rubex: Extended Ruby\n
  (('note:Rubex:Rubyを拡張'))
* Cython: Extended Python\n
  (('note:Cython:Pythonを拡張'))

How to runn(('note:動かし方'))

* Translate extension code to C\n
  (('note:拡張言語で書かれたコードをCにコンパイル'))
* Compile C code\n
  (('note:コンパイルされたCコードをビルド'))
* Load the built extension\n
  (('note:ビルドした拡張ライブラリーを読み込む'))

Extended syntaxn(('note:拡張された構文'))

* Type information\n
  (('note:型情報を書ける'))
* C code snippet\n
  (('note:Cのコードを書ける'))

How to run: Rubexn(('note:Rubexの動かし方'))

# coderay ruby
# fibonacci.rubex
class Fibonacci
  # "int" is type information
  def compute(int n)
    # ...
  end
end

How to run: Rubexn(('note:Rubexの動かし方'))

# coderay console
% rubex fibonacci.rubex
% cd fibonacci
% ruby extconf.rb
% make

How to run: Rubexn(('note:Rubexの動かし方'))

# coderay ruby
require_relative "fibonacci.so"
p Fibonacci.new.compute(100)

Extend language: Pros1n(('note:拡張言語:長所1'))

(('tag:center')) Friendly syntax forn base language usersn (('note:ベースの言語のユーザーにはなじみやすい構文'))

* Most syntax is the same\n
  (('note:構文の大部分は同じだから'))

Extend language: Pros2n(('note:拡張言語:長所2'))

(('tag:center')) Easy to migrate from base langn (('note:ベースの言語からの移行が容易'))

* Because upward compatibility\n
  (('note:上位互換だから'))
* Code for base language works without modification\n
  (('note:ベースの言語で書かれたコードは変更なしで動く'))

Extend language: Pros3n(('note:拡張言語:長所3'))

(('tag:center')) Doesn't require much C knowledgen (('note:そんなにCの知識は必要ない'))

* Most code can be written with base language knowledge\n
  (('note:コードの大部分はベースの言語の知識で書ける'))

Extend language: Cons1n(('note:拡張言語:短所1'))

(('tag:center')) You realize that it's not friendly syntax when you use itn (('note:使うとそんなになじみやすい文法ではないと気づく'))

* Small differences will confuse you\n
  (('note:小さな違いがいろいろあってわかりにくい'))

Extend language: Cons2n(('note:拡張言語:短所2'))

(('tag:center')) Difficult to debugn (('note:デバッグが難しい'))

* Need base language, extend language and C knowledge\n
  (('note:ベースの言語の知識も拡張言語の知識もCの知識も必要'))

(('note:Cython has GDB integration to solve this problem'))n (('note:Cythonはこの問題を解決するためにGDB用の便利機能を提供'))

Extend language: Cons3n(('note:拡張言語:短所2'))

(('tag:center')) Hard to maintainn (('note:(For maintainers, not for users)'))n (('note:(ユーザーではなくメンテナーが)メンテナンスが大変'))

* Base language introduces a new syntax then extend language should implement it\n
  (('note:ベースの言語が新しい構文を導入→拡張言語でも実装'))

Not based on Cn(('note:C言語以外をベースにする'))

* JRuby: Java + Ruby
* Helix: Rust + Ruby

How to run: JRubyn(('note:JRubyでの動かし方'))

# coderay java
// Fibonacci.java
public class Fibonacci {
  public long[] compute(int n) {
    // ...
  }
}

How to run: JRubyn(('note:JRubyでの動かし方'))

# coderay console
% javac Fibonacci.java
% jar cf fibonacci.jar Fibonacci.class

How to run: JRubyn(('note:JRubyでの動かし方'))

# coderay ruby
require "fibonacci.jar"
java_import "Fibonacci"
p Fibonacci.new.compute(100)

Not based on C: Pros1n(('note:C言語以外をベースにする:長所1'))

(('tag:center')) Easier to write than Cn (('note:Cより書きやすい'))

* Simpler syntax\n
  (('note:洗練された構文'))
* Rich features compared to C\n
  (('note:Cより機能が多い'))

Not based on C: Pros2n(('note:C言語以外をベースにする:長所2'))

(('tag:center')) Can use librariesn in base languagen (('note:ベース言語のライブラリーを使える'))

* Major languages have many libs\n
  (('note:広く使われている言語はライブラリーも多い'))

Not based on C: Cons1n(('note:C言語以外をベースにする:短所1'))

(('tag:center')) Need base language knowledgen (('note:ベース言語の知識が必要'))

* Java for JRuby(('note:(JRubyならJava)'))
* Rust for Helix(('note:(HelixならRust)'))

Not based on C: Cons2n(('note:C言語以外をベースにする:短所2'))

(('tag:center')) May need C knowledgen (('note:(When Ruby implementation is MRI)'))n (('note:Rubyの実装がMRIならCの知識が必要かもしれない'))

* Base language wraps Ruby C API\n
  (('note:ベースの言語はRubyのC APIをラップしている'))
  * e.g.: (({sys::RSTRING_PTR})) on Helix\n
    (('note:例:Helixならsys::RSTRING_PTRがラップしたAPI'))

Not based on C: Cons3n(('note:C言語以外をベースにする:短所3'))

(('tag:center')) Hard to maintainn (('note:(When Ruby implementation is MRI)'))n (('note:Rubyの実装がMRIならメンテナンスが大変かも'))

* Ruby introduces a new API then base language may need to implement it\n
  (('note:Rubyが新しいAPIを追加→ベース言語でも実装?'))
  * e.g.: (({rb_gc_adjust_memory_usage()}))

Provide convenient APIn(('note:便利なAPIを提供'))

* Rice: C++ + Ruby
* Ext++: C++11 + Ruby
* Boost.Python: C++ + Python
* pybind11: C++11 + Python

How to run: Ricen(('note:Riceの動かし方'))

# coderay cpp

#include <rice/Class.hpp>

static const char * // Not VALUE!
rb_sample_hello(Rice::Object self) {
  return "Hello";
}
extern "C" void Init_sample() {
  Rice::define_class("Sample").
    define_method("hello", &rb_sample_hello);
}

How to run: Ricen(('note:Riceの動かし方'))

# coderay ruby

# extconf.rb
require "mkmf-rice"
create_makefile("sample")

How to run: Ricen(('note:Riceの動かし方'))

# coderay console

% ruby extconf.rb
% make

How to run: Ricen(('note:Riceの動かし方'))

# coderay ruby

require_relative "sample.so"
p Sample.new.hello
# => "Hello"

Provide C++ API: Prosn(('note:C++ APIを提供:長所'))

Omitn (('note:省略'))

Provide C++ API: Consn(('note:C++ APIを提供:短所'))

Omitn (('note:省略'))

Provide C++ API: ConsNn(('note:C++ APIを提供:短所N'))

(('tag:center')) Conv from Ruby may be a bothern (('note:Ruby実装の移植が面倒'))

* C++ with convenient Ruby C API needs more code than Ruby\n
  (('note:RubyのC APIにC++の便利APIがあっても'))\n
  (('note:Rubyよりもたくさんコードが必要'))

From Ruby: Ricen(('note:RubyからRiceに移植'))

# coderay ruby
def fib(n)
  prev = 1
  current = 1
  1.step(n - 1).collect do
    prev, current = current, current + prev
    prev
  end
end

From Ruby: Ricen(('note:RubyからRiceに移植'))

# coderay cpp
std::vector<uint64_t> fib(Rice::Object self, int n) {
  uint64_t prev = 1, current = 1;
  std::vector<uint64_t> numbers;
  for (int i = 1; i < n; ++i) {
    auto temp = current; current += prev; prev = temp;
    numbers.push_back(prev);
  }
  return numbers;
}