Slide 1

Slide 1 text

Ruby, Opal and WebAssembly RubyKaigi2017 yhara (Yutaka Hara) RubyKaigi 2017 (19, Sep) 1

Slide 2

Slide 2 text

Myself • Yutaka Hara (@yhara) • http://yhara.jp • @ Matsue, Shimane RubyKaigi 2017 (19, Sep) 2

Slide 3

Slide 3 text

RubyKaigi 2017 (19, Sep) 3

Slide 4

Slide 4 text

Talks from 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 RubyKaigi 2017 (19, Sep) 4

Slide 5

Slide 5 text

My Book Available in the bookstore in the sponsors room RubyKaigi 2017 (19, Sep) 5

Slide 6

Slide 6 text

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) 1 "The" RubyKaigi was not held in this year RubyKaigi 2017 (19, Sep) 6

Slide 7

Slide 7 text

Agenda • 1. DXOpal • 2. DXOpal and WebAssembly • 3. Does WebAssembly change Rubyists' life? RubyKaigi 2017 (19, Sep) 7

Slide 8

Slide 8 text

1. DXOpal RubyKaigi 2017 (19, Sep) 8

Slide 9

Slide 9 text

Opal Ruby to JavaScript compiler http://opalrb.org RubyKaigi 2017 (19, Sep) 9

Slide 10

Slide 10 text

Opal Talks in RubyKaigi2017 • Day 1 / dRuby on Brower / Yoh Osaki • Day 2 / Yutaka Hara / Ruby, Opal and WebAssembly RubyKaigi 2017 (19, Sep) 10

Slide 11

Slide 11 text

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, ...) RubyKaigi 2017 (19, Sep) 11

Slide 12

Slide 12 text

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. 2 https://www.slideshare.net/mametter/ruby-65182128 (p.69) RubyKaigi 2017 (19, Sep) 12

Slide 13

Slide 13 text

Why Opal matters JavaScript ↓ Web App Desktop App (Electron) Mobile App (Cordova) ... RubyKaigi 2017 (19, Sep) 13

Slide 14

Slide 14 text

Why Opal matters Ruby→Opal→JavaScript ↓ Web App Desktop App (Electron) Mobile App (Cordova) ... RubyKaigi 2017 (19, Sep) 14

Slide 15

Slide 15 text

Why Opal matters Ruby→Opal→JavaScript ↓ Browser Games Visualizaiton RubyKaigi 2017 (19, Sep) 15

Slide 16

Slide 16 text

DXOpal • Opal port of DXRuby • DXRuby: Game Framework for Ruby on Windows • http://dxruby.osdn.jp/ • 2009~ • Simple and sufficient API RubyKaigi 2017 (19, Sep) 16

Slide 17

Slide 17 text

Making Opal Library # Goal Window.draw_circle(100, 100, 200, [0, 255, 0]) RubyKaigi 2017 (19, Sep) 17

Slide 18

Slide 18 text

Making Opal Library module DXOpal class Window def self.draw_circle(x, y, r, color) # ?? end end end RubyKaigi 2017 (19, Sep) 18

Slide 19

Slide 19 text

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 RubyKaigi 2017 (19, Sep) 19

Slide 20

Slide 20 text

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 RubyKaigi 2017 (19, Sep) 20

Slide 21

Slide 21 text

DEMO RubyKaigi 2017 (19, Sep) 21

Slide 22

Slide 22 text

DEMO 2 • Experimental: Physics simulation • powered by Matter.js RubyKaigi 2017 (19, Sep) 22

Slide 23

Slide 23 text

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 fx fx Chrome is not ok because it raises error when ajax'ing images from file:// RubyKaigi 2017 (19, Sep) 23

Slide 24

Slide 24 text

How dxopal-game works [index.html] [main.rb] | load ^ v | ajax [dxopal.min.js]-------+ RubyKaigi 2017 (19, Sep) 24

Slide 25

Slide 25 text

How dxopal-game works [index.html] [main.rb] | load ^ v | ajax [dxopal/**.rb] --> [dxopal.min.js]-------+ ^ | [opal/**.rb] ----------+ RubyKaigi 2017 (19, Sep) 25

Slide 26

Slide 26 text

Help wanted • More examples • Tutorial • Beautiful website https://github.com/yhara/dxopal/issues RubyKaigi 2017 (19, Sep) 26

Slide 27

Slide 27 text

opalrb-jp If you need help in Japanese: https://opalrb-jp-slack.herokuapp.com/ RubyKaigi 2017 (19, Sep) 27

Slide 28

Slide 28 text

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 RubyKaigi 2017 (19, Sep) 28

Slide 29

Slide 29 text

2. DXOpal and WebAssembly RubyKaigi 2017 (19, Sep) 29

Slide 30

Slide 30 text

DXRuby's Sprite class player = Sprite.new(100, 100, Image[:player]) SpriteʹImageʴCoordinatesʴCollision Checking RubyKaigi 2017 (19, Sep) 30

Slide 31

Slide 31 text

Collision detection is heavy • Each Sprite has a hit-area (point/circle/rectangle/triangle) • + scaling, rotation RubyKaigi 2017 (19, Sep) 31

Slide 32

Slide 32 text

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 RubyKaigi 2017 (19, Sep) 32

Slide 33

Slide 33 text

How about using WebAssembly? RubyKaigi 2017 (19, Sep) 33

Slide 34

Slide 34 text

JavaScript as compile target • Opal (Ruby) • Scala.js (Scala) • GopherJS (Go) • ClojureScript (Clojure) • OCamljs (OCaml) • Elm (Haskell-like) • ... RubyKaigi 2017 (19, Sep) 34

Slide 35

Slide 35 text

Emscripten • 2012~ • Compile C/C++ into JavaScript through LLVM IR [.c] | +------|-------+ | v | | [LLVM IR] | Emscripten | | | +------|-------+ v [.js] RubyKaigi 2017 (19, Sep) 35

Slide 36

Slide 36 text

JavaScript is not so good to be assembly 1. Performance predictability 2. Output size RubyKaigi 2017 (19, Sep) 36

Slide 37

Slide 37 text

1. Performance predictability • How to write fast JS program • is different among browsers (each has different JS engine) RubyKaigi 2017 (19, Sep) 37

Slide 38

Slide 38 text

What Emscripten needs • Ultra-fast arithmetic operations • A huge TypedArray (memory) • No objects • No methods RubyKaigi 2017 (19, Sep) 38

Slide 39

Slide 39 text

asm.js • Statically typed programming language • No objects • No methods RubyKaigi 2017 (19, Sep) 39

Slide 40

Slide 40 text

asm.js • Small subset of JS (asm.js program is polyglot of JS) • Example5e 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 } } 5e https://html5experts.jp/chikoski/18980/ RubyKaigi 2017 (19, Sep) 40

Slide 41

Slide 41 text

asm.js [ asm.js ] | | Run as JS | | Run as asm.js v v [Old Browser] [New Browser] RubyKaigi 2017 (19, Sep) 41

Slide 42

Slide 42 text

2. File size problem • Huge .js file • Downloading time • Parsing time • Optimizing time RubyKaigi 2017 (19, Sep) 42

Slide 43

Slide 43 text

Here comes WebAssembly • http://webassembly.org/ • Binary format • Less downloading time • Less parsing time • Less optimizing time RubyKaigi 2017 (19, Sep) 43

Slide 44

Slide 44 text

Summary JS asm.js WebAssembly Performance predictability bad good good Size (= load time) bad bad good RubyKaigi 2017 (19, Sep) 44

Slide 45

Slide 45 text

Browser support http://caniuse.com/#feat=wasm RubyKaigi 2017 (19, Sep) 45

Slide 46

Slide 46 text

DXOpal + WebAssembly • Use WebAssembly for collision detection • Original code (DXRuby) is written in C RubyKaigi 2017 (19, Sep) 46

Slide 47

Slide 47 text

Compile collision.c into WebAssembly • Cannot port entire C source (because of RB_ARRAY etc.) • Extract some functions RubyKaigi 2017 (19, Sep) 47

Slide 48

Slide 48 text

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]); }; RubyKaigi 2017 (19, Sep) 48

Slide 49

Slide 49 text

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...) RubyKaigi 2017 (19, Sep) 49

Slide 50

Slide 50 text

Demo RubyKaigi 2017 (19, Sep) 50

Slide 51

Slide 51 text

Important notice ! RubyKaigi 2017 (19, Sep) 51

Slide 52

Slide 52 text

WebAssembly is not designed to run faster than JavaScript http://2ality.com/2015/06/web-assembly.html RubyKaigi 2017 (19, Sep) 52

Slide 53

Slide 53 text

Demo RubyKaigi 2017 (19, Sep) 53

Slide 54

Slide 54 text

WebAssembly and run speed • WebAssembly is tree (non-linear) • Easier to implement to each browsers? RubyKaigi 2017 (19, Sep) 54

Slide 55

Slide 55 text

3. Does WebAssembly change Rubyists' life? RubyKaigi 2017 (19, Sep) 55

Slide 56

Slide 56 text

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++" hg hg http://webassembly.org/docs/high-level-goals/ 2. RubyKaigi 2017 (19, Sep) 56

Slide 57

Slide 57 text

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" RubyKaigi 2017 (19, Sep) 57

Slide 58

Slide 58 text

How to use WebAssembly with Ruby? • 1: Currently possible (C/C++/Rust -> WebAssembly) • 2: Possible in the future (Ruby -> WebAssembly) RubyKaigi 2017 (19, Sep) 58

Slide 59

Slide 59 text

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 RubyKaigi 2017 (19, Sep) 59

Slide 60

Slide 60 text

2: Possible in the future • Compiling Ruby into WebAssembly • It's not easy as it sounds! RubyKaigi 2017 (19, Sep) 60

Slide 61

Slide 61 text

How to compile Ruby into WebAssembly? • 1: Ruby is too dynamic • 2: Ruby is dynamically typed language • 3: Runtime issue • 4: GC issue? RubyKaigi 2017 (19, Sep) 61

Slide 62

Slide 62 text

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 RubyKaigi 2017 (19, Sep) 62

Slide 63

Slide 63 text

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) RubyKaigi 2017 (19, Sep) 63

Slide 64

Slide 64 text

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 RubyKaigi 2017 (19, Sep) 64

Slide 65

Slide 65 text

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) cr cr Problems 1, 2 are solved by Crystal but 3, 4 remain RubyKaigi 2017 (19, Sep) 65

Slide 66

Slide 66 text

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) RubyKaigi 2017 (19, Sep) 66

Slide 67

Slide 67 text

If you want to write entire code with Ruby: • You can use Opal! • http://opalrb.org/libraries/ • HyperLoop • ClearWater • Inasita • Menilite • Lissio • ... RubyKaigi 2017 (19, Sep) 67

Slide 68

Slide 68 text

Wrap up • DXOpal: Browser game framework for Ruby • WebAssembly is not a silver bullet • Don't wait for the future, use Opal now! RubyKaigi 2017 (19, Sep) 68

Slide 69

Slide 69 text

Appendix RubyKaigi 2017 (19, Sep) 69

Slide 70

Slide 70 text

PNaCl (Portable Native Client) • 2013~ • Implemented in Google Chrome • "safe, portable, high-performance apps without plugins" • Run native code in browser, securely • Discontinued ch ch https://blog.chromium.org/2017/05/goodbye-pnacl-hello-webassembly.html?m=1 RubyKaigi 2017 (19, Sep) 70

Slide 71

Slide 71 text

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) RubyKaigi 2017 (19, Sep) 71

Slide 72

Slide 72 text

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 RubyKaigi 2017 (19, Sep) 72

Slide 73

Slide 73 text

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) • https://github.com/crystal-lang/crystal/issues/829 RubyKaigi 2017 (19, Sep) 73