Skip to content

Instantly share code, notes, and snippets.

@yhara
Last active September 19, 2017 05:47
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save yhara/ac76db6d2bf0b9ea9701d67db3ac5bd5 to your computer and use it in GitHub Desktop.

footer: RubyKaigi 2017 (19, Sep) slidenumbers: true autoscale: true

Ruby, Opal and WebAssembly

RubyKaigi2017

inline

yhara (Yutaka Hara)


Myself

  • Yutaka Hara (@yhara)
  • http://yhara.jp
  • inline @ Matsue, Shimane

inline


Talks from inline member

  • Day 1 / Shugo Maeda / Handling mails on a text editor
  • Day 2 / Matz / Keynote
  • Day 2 / Yutaka Hara / Ruby, Opal and WebAssembly
  • Day 3 / Kouji Takao / Smalruby : The neat thing to connect Rubyists and Scratchers

^ 今回は弊社メンバーのトークが4つあります。(まつもとさんはすごくいろんな会社の名刺をお持ちですけど、弊社を辞められたわけじゃないですからね!月に数回は松江のオフィスに来られています)


My Book

Available in the bookstore in the sponsors room

right fit

^ 私の本です。会場で買えます。


Me on RubyKaigi

  • 2007: Ruby/SDLとその周辺 (with Obayashi-san)
  • 2009: Ruby製アプリケーションを配布するn個の方法
  • 2011: Rubyマスターへの道
  • 2012: DIY Programming1
  • 2015: Let's Make a Functional Language!
  • 2017: Ruby, Opal and WebAssembly

(see http://yhara.jp/Presentations for other events)

^ RubyKaigiには、今年で6回目くらいの登壇になります。直近だと2年前に関数型言語をつくろうという話をしています。


Agenda

    1. DXOpal
    1. DXOpal and WebAssembly
    1. Does WebAssembly change Rubyists' life?

^ 本日のアジェンダです。最初に私が作っているDXOpalというものの紹介をします。そのあとWebAssemblyの話をして、最後に未来の話をします。


1. DXOpal

^ では、DXOpalの話をしましょう。


Opal

Ruby to JavaScript compiler http://opalrb.org

inline

^ まず、Opalというものを知っている人、どれくらいいますか?

^ OpalはRubyからJavaScriptへのコンパイラです。つまりOpalを使えば、Rubyを使ってブラウザ内の処理を実装できるのです。


Opal Talks in RubyKaigi2017

  • Day 1 / dRuby on Brower / Yoh Osaki
  • Day 2 / Yutaka Hara / Ruby, Opal and WebAssembly

^ 今回のRubyKaigiではOpalのセッションが2つあります。一つは昨日の@youchanさんの発表でした。


Why don't you try Opal?

  • Just didn't know (now you know :-)
  • Lack of library? (compared to tons of JS libs)
  • Happy with ES6+? (classes, arrow syntax, ...)

^ ところが、まだそんなに多くの人がOpalを使っているわけではないですよね。なぜなんでしょうか?

^ まあ単純に存在を知らなかったのかもしれません。そういう人は今知りましたね。

^ あるいは、使いたいライブラリがないからかもしれません。JavaScriptにはフロントエンド用のライブラリだけでも覚えきれないほど存在するので、これは仕方のないところです。

^ あるいは、JSで満足しているからかもしれません。最近はJavaScriptにもクラスが入ったり、アロー記法が入ったり、昔よりずっと便利になってますよね。


Why Ruby matters (to me)

  • I don't hate JavaScript. I'm just too fluent in Ruby :-)
  • "Cached in my brain" 2
    • Hash, Enumerable#flat_map, etc.

^ とはいえですね、僕にとってはRubyで書けるというのは重要なことなんです。JavaScriptはそこまで嫌いではないですけど、なんだかんだでRubyが一番慣れてるんですよね。

^ いま裏で話している遠藤さんがそういう話をしてたことがあるんですけど、その言葉を借りれば、「脳のキャッシュに乗っている」というやつです。

^ JavaScriptも書けないわけではないですけど、Rubyのメソッドやデータ構造が欲しくなることはあります。Hashとか、Enumerableの便利メソッドとか。


Why Opal matters

          JavaScript
              ↓
           Web App
         Desktop App (Electron)
          Mobile App (Cordova)
            ...


Why Opal matters

Ruby→Opal→JavaScript
              ↓
           Web App
         Desktop App (Electron)
          Mobile App (Cordova)
            ...

^ 僕がOpalを重要視している理由はそういうところにあります。Opalがあれば、JavaScriptでできるいろいろなことがRubyでもできることになる。


Why Opal matters

Ruby→Opal→JavaScript
              ↓
         Browser Games
         Visualizaiton

^ そういうわけでOpalの使いみちを日々いろいろと考えているのですけど、今回やってみたのが、ブラウザでゲームや簡単な可視化を行うためのライブラリをOpalで作るというものです。


DXOpal

  • Opal port of DXRuby
  • DXRuby: Game Framework for Ruby on Windows

^ DXOpal(ディーエックスオパール)というのがプロジェクトの名前です。もともとDXRubyという、Windows用のRubyのゲームライブラリがあるんですけど、ふとこれOpalに移植できそうだなと思って。

^ DXRubyのいいところは、APIが「ちょうどいい」ことです。

^ ゲームのライブラリは設計が難しくて、低レベルすぎると簡単なことをするのにもたくさんのコードが必要になります。一方で高レベルすぎると使い方を覚えるのが大変になります。DXRubyは私も使ったことがありますが、そのあたりのバランスがとても良いと思います。


Making Opal Library

  # Goal
  Window.draw_circle(100, 100, 200, [0, 255, 0])

^ DXOpalをどうやって作ったか、少しだけ紹介したいと思います。 ^ まずゴールですが、DXRubyではdraw_circleという命令で円を描くことができるので、同じようにしたいと思います。


Making Opal Library

module DXOpal
  class Window
    def self.draw_circle(x, y, r, color)
      # ??
    end
  end
end

^ それにはまず、Opal側でもWindow.draw_circleというメソッドを定義します。で、この中に何を書くかですが、ここでcanvasを使って円を描きたいのですよね。


Making Opal Library

module DXOpal
  class Window
    def self.draw_circle(x, y, r, color)
      %x{
        ...
        ctx.arc(x, y, r, 0, Math.PI*2, false);
        ...
      }
    end
  end
end

^ Opalでは%x(パーセント エックス)を書くとその中だけ生のJavaScriptが書けるという機能があるので、それを使います。

^ こんな感じで、ブラウザのAPIを叩く部分だけ%xを使うことで、canvasなどのAPIをRubyでラップしていきます。


Compatibility

https://github.com/yhara/dxopal/blob/master/TODO.md

class DXRuby DXOpal
module Input OK Basically (TODO: pad support)
module Window OK Basically
class Font OK Basically
class Image OK Basically
class Sound OK Basically
class SoundEffect OK Basically
class Sprite OK Ongoing (TODO: collision detection)
class RenderTarget OK N/A
class Shader OK N/A
class Shader::Core OK N/A

^ どれくらい移植できてるかですが、基本的な部分は既に実装を終えています。描画、入力、音声ですね。 ^ それ以外には、SoundEffectというちょっと変わった機能とかも移植しています。これは音の波形を計算するコードを書くと効果音が鳴らせるという機能なのですが、WebAudioを使ったら移植できました。 ^ 下の3つは3D関係のものとかで、移植の予定はありません。ただWebGLとか使えば移植自体はできそうな気がするので、プルリクエストをお待ちしています。


DEMO

^ このように、簡単なゲームが作れるくらいにはなっています。


DEMO 2

  • Experimental: Physics simulation
    • powered by Matter.js

inline

^ あとDXOpalの独自機能で、物理演算に対応させてみました。Matter.js(マッタージェーエス)というJavaScriptの物理計算エンジンがあって、それを組み込んでみました。


DEMO 3

  • You don't need to install Ruby!
    1. Download and unpack dxoapl-game-x.y.z.zip
    2. Edit main.rb
    3. Open index.html with Firefox 3

^ もう一つDXOpalのセールスポイントとして、Rubyをインストールしなくてもゲームが作れる!というのがあります。

^ zipを解凍して中のindex.htmlを開くと、ゲームが動きます。


How dxopal-game works

                      [index.html]       [main.rb]
                          | load            ^
                          v                 | ajax
                      [dxopal.min.js]-------+

^ さて、どうなっているのでしょうか?zipに入っているのはhtmlと、.jsと、main.rbだけです。main.rbを動かすためにはRubyが必要そうに見えますが、Rubyはどこにあるのでしょうか?


How dxopal-game works

                      [index.html]       [main.rb]
                          | load            ^
                          v                 | ajax
   [dxopal/**.rb] --> [dxopal.min.js]-------+
                          ^
                          |
   [opal/**.rb] ----------+

^ 実はこのdxopal.min.jsというファイルに、「Opal自身をJSにコンパイルしたもの」が丸ごと入っているのです。OpalはRubyからJSへのコンパイラで、OpalはすべてRubyで書かれているので、Opal自体をJSにコンパイルするということができるのです。

^ Rubyのインストールは、現在ではそこまで大変でもないですけど、学校とかで自由にインストールができない環境もあると思うので、解凍するだけでプログラミングが始められることが役立つ場面があるといいなと思っています。


Help wanted

  • More examples
  • Tutorial
  • Beautiful website

https://github.com/yhara/dxopal/issues

^ DXOpalの今後ですが、手伝ってほしいことは、宣伝が苦手なので、広めてくれる人がいると嬉しいですね。サンプルを作るとか、チュートリアル記事を書いてくれるとか、ウェブサイトを綺麗にしてくれるとか。


opalrb-jp

If you need help in Japanese:

https://opalrb-jp-slack.herokuapp.com/

^ 触ってみたけど動かなかった、という場合は、日本語のチャットがあるので、そこで聞いてもらうこともできます。もちろんDXOpal以外のOpalの質問も大丈夫です。


TODOs left for DXOpal v0.4.0

  • Collision checking feature is unfinished yet
    • (Mostly because I've been writing this slide :-P)
  • Let's talk about that

^ DXOpalの次のバージョンは0.4なんですけど、まだリリースできません。当たり判定の処理が移植できてないからです(スライド書いてたからですけど、、)。その話をしましょう。


2. DXOpal and WebAssembly

^ Opalで性能が問題になった箇所と、その解決策について話します。


DXRuby's Sprite class

player = Sprite.new(100, 100, Image[:player])

Sprite=Image+Coordinates+Collision Checking

^ DXRubyの機能の一つに、Spriteというクラスがあります。Spriteは画像と座標をひとまとめにしたもので、画面上のプレイヤーや敵キャラクターなどをそれぞれ1つのSpriteとすることで、プログラムが書きやすくなるというものです。


Collision detection is heavy

  • Each Sprite has a hit-area (point/circle/rectangle/triangle)
    • scaling, rotation

^ このSpriteクラスをOpalに移植するにあたって、一つ困ることがありました。それは当たり判定の計算が重たいことです。

^ それぞれのSpriteは、当たり判定エリアを設定することができます。その形は点、円、長方形、三角形のいずれかです。

^ さらに各Spriteは拡大・縮小したり、回転したりできるので、当たり判定もそれに合うよう計算する必要があります。


Opal is not so fast (as JavaScript)

# Ruby
cx = (x1 + x2 + x3) / 3                              
// Compiled JavaScript
cx = $rb_divide(($rb_plus($rb_plus(x1, x2), x3)), 3);

Because you can "add" Strings or Arrays in Ruby

^ Opalで書いたRubyのコードは、残念ながらJavaScriptよりは少し遅くなります。例えば上は3つのx座標の真ん中を求めるというRubyのコードですが、これをOpalでコンパイルすると下のようなJavaScriptになります。長いですよね。

^ というのは、Rubyのプラス記号は文字列や配列にも使われるからです。そのためx+yというRubyコードは、$rb_plus(ダラー・アールビー・プラス)という特別な関数の呼び出しにコンパイルされます。 ^ このようにOpalではRubyの仕様を忠実に再現するため、素のJavaScriptよりも少し遅くなります。


How about using WebAssembly?

^ そこで、このあたり判定の部分だけWebAssemblyを導入したらどうかなというのを考えました。この時点ではWebAssemblyのことはよく分かってなかったのですが、アセンブリって付いてるしなんか速そうだなと。


JavaScript as compile target

  • Opal (Ruby)
  • Scala.js (Scala)
  • GopherJS (Go)
  • ClojureScript (Clojure)
  • OCamljs (OCaml)
  • Elm (Haskell-like)
  • ...

^ ということで、まずWebAssemblyがどういうものなのか説明します。

^ 現代のJavaScriptは単にブラウザ組み込みのプログラミング言語というだけでなく、別のプログラミング言語をコンパイルするターゲットであるという側面があります。 ^ Opalもそうですし、Scala.jsとかいろんな言語がJavaScriptにコンパイルされるようになっています。


Emscripten

  • 2012~
  • Compile C/C++ into JavaScript through LLVM IR
        [.c]
         |
  +------|-------+
  |      v       |
  |   [LLVM IR]  | Emscripten
  |      |       |
  +------|-------+
         v
       [.js]

^ そんな中2012年に登場したのが、Emscriptenというプロダクトです。これは、C言語のプログラムをLLVM IRを経由してJavaScriptに変換するというものです。

^ (IR: Intermediate Representation, 中間表現)


JavaScript is not so good to be assembly

  1. Performance predictability
  2. Output size

^ しかし、C言語をJSにコンパイルするのには2つの問題がありました。それぞれ見ていきましょう。


1. Performance predictability

  • How to write fast JS program
    • is different among browsers (each has different JS engine)

^ 一つ目の問題は、速いJavaScriptを書く方法がブラウザによって違うという問題です。JavaScriptは変数に型がないので、最適化がけっこう難しいのですよね。そこをブラウザベンダ各社がそれぞれ頑張っているのですが、結果として、どのような書き方をするのが速いのかはブラウザによって違いが出ます。これは、Emscriptenみたいなプロジェクトにとっては困りますよね。ブラウザごとに別のJSを出力するのも大変だし。


What Emscripten needs

  • Ultra-fast arithmetic operations
  • A huge TypedArray (memory)
  • No objects
  • No methods

^ そもそもEmscriptenがコンパイルを行うとき、JSの言語機能のほとんどは使わないんですよね。大きなTypedArrayがあって、高速な数値計算ができればいい。オブジェクトもメソッドもいらない。


asm.js

  • Statically typed programming language
  • No objects
  • No methods

^ そこで考案されたのがasm.jsというプログラミング言語です。asm.jsは静的型付けで、オブジェクトもメソッドもありません。


asm.js

  • Small subset of JS (asm.js program is polyglot of JS)
  • Example4
function AddFunctions(){
  "use asm";
  function add1(value){
    value = value | 0;  // Declare `value` is int
    var result = 0;
    result = (value + 1) | 0;
    return result;
  }
  return {
    add1: add1
  }
}

^ それだけだとどこがjs?って感じですが、実は見た目がまんまJSなんですね。

^ 見た目だけではなく、asm.jsは「JSとしても」解釈できるよう、巧妙に設計されています。例えば「value = value | 0」(バリューイコールバリューオアゼロ)という謎の記述は、引数valueがint型であることを明示するための記法です。


asm.js

             [ asm.js ]
              |     |
   Run as JS  |     | Run as asm.js
              v     v
   [Old Browser]    [New Browser]

^ asm.jsは、JavaScriptのサブセットなので、対応していないブラウザでもJavaScriptとして動かすことができます。


2. File size problem

  • Huge .js file
  • Downloading time
  • Parsing time
  • Optimizing time

^ もう一つ問題になったのが出力されるJavaScriptのサイズです。Emscriptenでゲームのような実用的なプログラムをコンパイルすると、巨大な.jsファイルが出力されます。サイズが大きいとダウンロードに時間がかかりますし、ダウンロードしてからも、パースや最適化に時間がかかります。


Here comes WebAssembly

^ これを解決するのが、新たなフォーマットであるWebAssemblyです。

^ WebAssemblyは、C言語などのコンパイル先として設計された専用のバイナリフォーマットなので、.jsにコンパイルするのと比べてサイズが小さくなり、それによってダウンロード時間、パース時間、最適化時間のいずれも速くなります。


Summary

                       | JS   | asm.js | WebAssembly

---------------------------|------|--------|------------ Performance predictability | bad | good | good Size
(= load time) | bad | bad | good

^ 2つの問題についてまとめたものがこれです。asm.jsが1つ目の問題を解決し、WebAssemblyが2つ目の問題も解決したということですね。


Browser support

http://caniuse.com/#feat=wasm

inline

^ あとは、WebAssemblyは主要なブラウザのほとんどで動くというのも重要なところです。今後が楽しみですね。


DXOpal + WebAssembly

  • Use WebAssembly for collision detection
  • Original code (DXRuby) is written in C

^ で、当たり判定の部分にWebAssemblyを組み込んでみました。都合のいいことに、移植元となるDXRubyはRubyの拡張ライブラリとしてC言語で書かれています。


Compile collision.c into WebAssembly

  • Cannot port entire C source (because of RB_ARRAY etc.)
  • Extract some functions

^ ここで問題となるのは、DXRubyのどの範囲を持ってくるかです。残念ながら、DXRuby全体をWebAssemblyにコンパイルすることはできませんでした。というのは、DXRubyはRubyの拡張ライブラリなので、RB_ARRAYなどRubyのデータ構造を入力としているからです。

^ そこで今回は、当たり判定を行う部分だけをWebAssembly化することにしました。


Compile collision.c into WebAssembly

// (...snip...)

#define check_line_line( x1,  y1,  x2,  y2,  x3,  y3,  x4,  y4) \
  ( !((((x1 - x2) * (y3 - y1) + (y1 - y2) * (x1 - x3)) * \
            ((x1 - x2) * (y4 - y1) + (y1 - y2) * (x1 - x4)) > 0.0) || \
           (((x3 - x4) * (y1 - y3) + (y3 - y4) * (x3 - x1)) * \
            ((x3 - x4) * (y2 - y3) + (y3 - y4) * (x3 - x2)) > 0.0 )))

int check_triangle_triangle(float ox[3], float oy[3], float dx[3], float dy[3]) {
  return check_line_line(ox[0], oy[0], ox[1], oy[1], dx[1], dy[1], dx[2], dy[2]) ||
         check_line_line(ox[0], oy[0], ox[1], oy[1], dx[2], dy[2], dx[0], dy[0]) ||
         check_line_line(ox[1], oy[1], ox[2], oy[2], dx[0], dy[0], dx[1], dy[1]) ||
         check_line_line(ox[1], oy[1], ox[2], oy[2], dx[2], dy[2], dx[0], dy[0]) ||
         check_line_line(ox[2], oy[2], ox[0], oy[0], dx[0], dy[0], dx[1], dy[1]) ||
         check_line_line(ox[2], oy[2], ox[0], oy[0], dx[1], dy[1], dx[2], dy[2]) ||
         check_point_triangle(ox[0], oy[0], dx[0], dy[0], dx[1], dy[1], dx[2], dy[2]) ||
         check_point_triangle(dx[0], dy[0], ox[0], oy[0], ox[1], oy[1], ox[2], oy[2]);
};

^ これは、三角形どうしが衝突しているかを確かめるコードです。


Compile collision.c into WebAssembly

0000000 00 61 73 6d 01 00 00 00 01 95 80 80 80 00 02 60
0000010 08 7d 7d 7d 7d 7d 7d 7d 7d 01 7f 60 04 7f 7f 7f
0000020 7f 01 7f 03 83 80 80 80 00 02 00 01 04 84 80 80
0000030 80 00 01 70 00 00 05 84 80 80 80 00 01 00 99 01
0000040 07 bb 80 80 80 00 03 06 6d 65 6d 6f 72 79 02 00
0000050 14 63 68 65 63 6b 5f 70 6f 69 6e 74 5f 74 72 69
0000060 61 6e 67 6c 65 00 00 17 63 68 65 63 6b 5f 74 72
0000070 69 61 6e 67 6c 65 5f 74 72 69 61 6e 67 6c 65 00
0000080 01 09 81 80 80 80 00 00 0a b6 8a 80 80 00 02 e4
0000090 81 80 80 00 02 01 7f 04 7d 02 7f 41 00 21 08 02
(...snip...)

^ WebAssemblyにコンパイルするとこうなります(読めないと思いますが)。


Demo

^ デモ:Opal版の当たり判定でFPSがあまり出ないのが、WebAssembly版にすると60FPS出るようになります


Important notice 😳

^ ところがここで一つ、重要な話があります。それは、WebAssemblyの実行速度は別に速くないという話です。


WebAssembly is not designed to run faster than JavaScript

http://2ality.com/2015/06/web-assembly.html

inline

^ WebAssemblyが速いというのはロード時間の話で、実行時間はJavaScriptと同じくらいなのです。


Demo

^ デモ:実際に確かめてみましょう。


WebAssembly and run speed

  • WebAssembly is tree (non-linear)
    • Easier to implement to each browsers?

^ マニアックな話になりますが、WebAssemblyは「アセンブリ」という名前が付いていますが、アセンブリ言語のように命令が一直線に並んでいるという形ではなく、木構造の形をしています。アセンブラにはそれほど似ていないのですね。

^ それでは何に似ているかというと、実は「下処理したあとのJavaScript」に似ています。こうすると何が良いかというと、ブラウザベンダ各社がWebAssembly専用の実行系を用意するのではなく、既存のJavaScript処理系の下回りを再利用することができるのですね。


3. Does WebAssembly change Rubyists' life?

^ 最後に、未来の話をします。


Does WebAssembly change Rubyists' life?

  • For example, can we use Ruby instead of React, etc.?
  • The official WebAssembly site says:
    • "including support for languages other than C/C++" 5

^ WebAssemblyはRubyistの生活を変えるのでしょうか。例えば、Reactの代わりにRubyを使ったりできるようになるのでしょうか?実際WebAssemblyの公式サイトにも、将来的にはC以外の言語をサポートすると書いてあります。


What WebAssembly can do

  • New compile target for the web
    • Better loading time (cf. JS, asm.js)
  • C/C++/Rust is supported now
  • Ruby is not supported "yet"

^ まず、WebAssemblyに何ができるのかおさらいしましょう。WebAssemblyはブラウザで動く新しいコンパイルターゲットで、JavaScriptやasm.jsとくらべてロード時間が速いというメリットがあるのでした。 ^ コンパイル元言語としては、いまのところC, C++, Rustがサポートされています。 ^ Rubyはまだサポートされていません。


How to use WebAssembly with Ruby?

  • 1: Currently possible (C/C++/Rust -> WebAssembly)
  • 2: Possible in the future (Ruby -> WebAssembly)

^ ということで、今できることと、将来できるかもしれないことで分けて考えましょう。


1: Currently possible

  • Opal + WebAssembly (like DXOpal)
  • But DXOpal's case was not so meaningful
    • Same execution speed, easy to port to JS
  • Could be meaningful when:
    • Original C code is too long to port
    • Original C code is too complex to port (eg. cryptography, WebUSB)
    • Original C code is changed constantly

^ 今すぐできることは、Opalでアプリを書いて一部だけWebAssemblyを使うというパターンです。DXOpalのケースですね。 ^ ただしDXOpalの場合はあんまり意味がありませんでした。実行速度は変わらないし、JSにポートするのもそんなに難しくなかったので。 ^ ということはこれの逆を考えると、WebAssemblyが役に立つケースが見えてきます。もとのCコードが規模が大きくてポートしたくないとき。もとのCコードが複雑すぎてJSにポートできないとき。もとのCコードが頻繁に更新されるとき。


2: Possible in the future

  • Compiling Ruby into WebAssembly
    • It's not easy as it sounds!

^ 次に、将来の話です。Rubyも将来的にWebAssemblyで動かせるようになるのかなと思ってたんですが、本当に可能なのでしょうか。また、できたとしてOpalよりよいものになるのでしょうか。


How to compile Ruby into WebAssembly?

  • 1: Ruby is too dynamic
  • 2: Ruby is dynamically typed language
  • 3: Runtime issue
  • 4: GC issue?

^ RubyをWebAssemblyにコンパイルするには、大きく分けて4つの問題があります。


How to compile Ruby into WebAssembly?

  • 1: Ruby is very dynamic
    • Features to evaluate code in runtime (instance_eval, etc.)
    • a) Embed entire Ruby processor into WebAssembly
    • b) Restrict some dynamic features

^ 一つ目はRubyがとても動的であることです。例えばinstance_evalのように、実行時にコードを評価するような機能があります。 ^ 対処法としては、Ruby処理系全体をWebAssemblyにするか、あるいはこのような動的な機能を部分的に制限するという方法が考えられます。


How to compile Ruby into WebAssembly?

  • 2: Ruby is dynamically typed language
    • Hard to "compile" into statically typed language
    • a) Wrap everything with struct (very slow)
    • b) Type inference, type annotation
    • c) Use Ruby-like static language (Crystal)

^ 二つ目はRubyが動的型付き言語であることです。動的型言語を静的型言語にコンパイルするのは簡単ではありません。例えばRubyをC言語にコンパイルする話ってあんまり聞かないですよね?OpalはRubyのコンパイラですけど、変換先がJavaScriptで、動的型言語なんですよね。

^ 対処法としては、すべてを構造体でラップするという方法がありますが、実行速度がとても遅いはずです。数値aとbを足し算するのにも、いったんaをアンラップして、bをアンラップして、中身の数値を足し算して、結果をまたラップするという手順になるからです。

^ もう一つの対処法としては、型推論・型注釈と組み合わせるとかでしょうか。

^ あとは、RubyではなくRubyに似た静的型言語を使うという方法があります。Crystalのことですけど。Crystalの話はあとでまたします。


How to compile Ruby into WebAssembly?

  • 3: Runtime issue
    • Network, etc. cannot be accessed directly from WebAssembly
    • So some corelib/stdlibs (like Net::HTTP) need porting

^ 三つ目の問題は、ランタイムをどうするかです。WebAssemblyからは直接ハードウェアやネットワークにアクセスできないので、Rubyのライブラリのうち、そういう機能を使うものは移植が必要です。コンパイルし直すだけでは動きません。


How to compile Ruby into WebAssembly?

  • 4: GC issue
    • You cannot walk stack of WebAssembly
    • Future plan: https://github.com/WebAssembly/design/issues/1079
    • This affects Crystal (GH #829) 6

^ 四つ目の問題は、WebAssemblyがGCをまだサポートしていないことです。C/C++/Rustがサポートされていると言いましたが、RustはGCがないのでサポートできてるんですよね。 ^ これは将来的にはサポートが入る予定です。 ^ Crystalがこれの影響を受けています。Crystalだと問題1,2が解決されるんですけど、問題3,4は解決されない、という形ですね。


Do we need to compile Ruby into WebAssembly?

  • We have Opal already!
    • to run Ruby code on the browser
    • (One possible difference: WebAssembly-Ruby may run Ruby's C-extensions)

^ まあそんな感じで、RubyをWebAssemblyにコンパイルするのっていろいろ大変そうなんですが、そもそもRubyをWebAssemblyにコンパイルする必要があるんでしょうか? ^ やりたいのは、Rubyをブラウザで動かす、ということだったはずです。そうであれば、既にOpalを使うことができます。

^ (一応、違いとしてはWebAssemblyならC拡張が動くかもしれない、という違いはありますが)


If you want to write entire code with Ruby:

  • You can use Opal!
    • http://opalrb.org/libraries/
    • HyperLoop
    • ClearWater
    • Inasita
    • Menilite
    • Lissio
    • ...

^ しかしRubyでWebのフロントエンドを書くことは、実はいまでも可能です。というのはOpalがあるからです。そのような未来に興味がある人は、Opal製のWebフレームワークを試してみると良いでしょう。


Wrap up

  • DXOpal: Browser game framework for Ruby
  • WebAssembly is not a silver bullet
    • Don't wait for the future, use Opal now!

Questions: twitter.com/yhara

^ まとめです。今日は私が作っているDXOpalというRubyでブラウザゲーム作るやつを紹介しました。またそれをきっかけに、WebAssemblyとRubyの関わりについて考えてみました。 ^ WebAssemblyは銀の弾丸ではなく、単にブラウザでRubyが動いてハッピー、という話にはならなさそうです。そういうことがしたい場合はOpalを使いましょう。


Appendix

^ 予備スライドです(質疑応答用)


PNaCl (Portable Native Client)

  • 2013~
  • Implemented in Google Chrome
  • "safe, portable, high-performance apps without plugins"
  • Run native code in browser, securely
  • Discontinued 7

^ PNaClの説明


Toolchains

[A] Using emcc (Compile through asm.js)

    .c ---------> .ll ----------> asm.js ----------> .wasm
        Clang         Emscripten          binaryen
                                          (asm2wasm)

[B] Using LLVM (Experimental)

    .c ---------> .ll ----------> .s     ----------> .wasm
        Clang            LLVM             binaryen
                                          (s2wasm)

^ ツールの話(2種類の方法がある)


Non-web context

  • Interesting possible usage of WebAssembly-Ruby: Run on Node.js on AWS lambda (which does not support Ruby)
  [WebAssembly] <- [*.rb]
       |
   [Node.js]
       |
  [AWS lambda]
  • But Net::HTTP, etc. must be ported to use aws-sdk gem
    • eg. By using Node's API

^ ちょっと面白かった例


Crytal -> WebAssembly?

  • Crystal -> LLVM IR -> WebAssembly
  • What is needed
    • WebAssembly's GC support
    • Port some corelib/stdlib for WebAssembly
    • Output LLVM IR for WebAssembly? (I'm not sure)
  • crystal-lang/crystal#829

^ CrystalがWebAssemblyを吐く可能性はあるか。

Footnotes

  1. "The" RubyKaigi was not held in this year

  2. https://www.slideshare.net/mametter/ruby-65182128 (p.69)

  3. Chrome is not ok because it raises error when ajax'ing images from file://

  4. https://html5experts.jp/chikoski/18980/

  5. http://webassembly.org/docs/high-level-goals/ 2.

  6. Problems 1, 2 are solved by Crystal but 3, 4 remain

  7. https://blog.chromium.org/2017/05/goodbye-pnacl-hello-webassembly.html?m=1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment