Slide 1

Slide 1 text

C++ 視点からの Ruby 紹介 @seanchas̲t

Slide 2

Slide 2 text

内容 C++ を使っている人向けに Ruby の概要を紹介 C++ と Ruby は思想が対照的 C++ 実行効率重視 Ruby 開発効率重視 C++ と Ruby は使い所がかぶらないことが多い Ruby で低レイヤ開発はしない C++ で Web アプリは作らない 比べると面白いかもしれない

Slide 3

Slide 3 text

自己紹介 Twitter: 情報工学科 2 年 結構長い間 Qt+C++ でお絵かきソフト作ってた 最近は Ruby をよく書いてる @seanchas̲t PaintField

Slide 4

Slide 4 text

目次 処理系 値とクラス メソッド クラスとモジュー ル ブロック 例外 メタプログラミング テスト

Slide 5

Slide 5 text

処理系

Slide 6

Slide 6 text

C++ ネイティブコー ドへのコンパイラが基本 GCC Clang VC++ ... C++/CLI

Slide 7

Slide 7 text

Ruby MRI (CRuby) 公式実装 バー ジョン 2.1.1 r u b y コマンド

Slide 8

Slide 8 text

Ruby JRuby JVM で動く Java コー ドを呼べる IronRuby .NET で動く DLR (Dynamic Language Runtime)   ベー ス C# コー ドを呼べる dynamic で C# から IronRuby も呼べる

Slide 9

Slide 9 text

REPL Run‑Eval‑Print‑Loop 一行ずつコー ドを読み込んで実行、 結果を表示 irb 標準 pry 色々 便利 [ 6 ] p r y ( m a i n ) > 1 + 2 = > 3

Slide 10

Slide 10 text

値とクラス

Slide 11

Slide 11 text

動的型付け Ruby は動的型付き言語 変数に型は紐付いていない 値そのもの( オブジェクト) に 型( クラス) が紐付いている Ruby には変数宣言はなし x = 1 0 y = ' f o o ' y . c l a s s # = > S t r i n g y = x y . c l a s s # = > F i x n u m

Slide 12

Slide 12 text

すべてが参照 値とポインタの区別はない すべて参照型 ( ポインタ ) どこからも参照されなくなったオブジェクトは GC される

Slide 13

Slide 13 text

すべてがオブジェクト Ruby にはプリミティブ型は存在しない すべてのクラスは Object ( あるいは BasicObject) を継承 数値にもメソッドが使える - 1 . a b s # = > 1 1 0 . t i m e s d o p u t s ' h e l l o ' e n d

Slide 14

Slide 14 text

構文

Slide 15

Slide 15 text

unless 文 if not を表す i f f o o p u t s ' f o o ' e n d u n l e s s f o o p u t s ' n o t f o o ' e n d

Slide 16

Slide 16 text

後置 if / unless 節が 1 文のみの場合、 if / unless を後置できる p u t s ' f o o ' i f f o o p u t s ' n o t f o o ' u n l e s s f o o

Slide 17

Slide 17 text

値を返す if / unless 節の最後の文の値を返す s t r = i f f o o p u t s ' r e t u r n i n g " f o o " ' ' f o o ' e l s e p u t s ' r e t u r n i n g " n o t f o o " ' ' n o t f o o ' e n d

Slide 18

Slide 18 text

while / until until は while not を表す if と同様に後置が可能 w h i l e c o n d p u t s ' l o o p ' e n d u n t i l c o n d p u t s ' l o o p ' e n d p u t s ' l o o p ' w h i l e c o n d

Slide 19

Slide 19 text

break / next / redo いずれもルー プ内で使う break ルー プから抜ける C++ の break next 次の繰り返しに移る C++ の continue redo 同じ繰り返しを再度実行する C++ にはない

Slide 20

Slide 20 text

break / next / redo w h i l e t r u e i n p u t = g e t s . t o _ i c a s e i n p u t w h e n 1 b r e a k w h e n 2 n e x t w h e n 3 r e d o e n d e n d

Slide 21

Slide 21 text

case 値を指定して合致した節を実行 C++ の switch と似ているがより強力 値、 クラス、 正規表現などでマッチさせられる c a s e v a l u e w h e n 1 , 2 p u t s ' v a l u e = 1 o r 2 ' w h e n ' h o g e h o g e ' p u t s ' v a l u e = " h o g e h o g e " ' w h e n F l o a t p u t s ' v a l u e は浮動小数点数' w h e n / p a t t e r n / p u t s ' 正規表現/ p a t t e r n / にマッチ' e l s e p u t s ' それ以外' e n d

Slide 22

Slide 22 text

String interpolation 文字列リテラルの中に式を記述して 評価結果を文字列化して埋め込む " 1 + 1 = # { 1 + 1 } " = > " 1 + 1 = 2 "

Slide 23

Slide 23 text

制御構造で 真になる値・ 偽になる値 nil, false 偽 nil は null の意味 それ以外 真 0 も真

Slide 24

Slide 24 text

| | / & & a | | b a ? a : b a & & b a ? b : a それぞれ同じ Ruby では | | / & & は真偽値ではなくオブジェクトを返 す

Slide 25

Slide 25 text

nil ガー ド | | / & & 演算子を使って nil を綺麗に扱う a | | = b # a がなかったらb を代入 a & & = a . n a m e # a があればa をa . n a m e にする

Slide 26

Slide 26 text

メソッド

Slide 27

Slide 27 text

メソッド d e f a d d ( a , b ) a + b e n d a d d ( 1 , 2 ) # = > 3 a d d 1 , 2 # = > 3 C++ の関数・ メンバ関数にあたるもの 最後の式が暗黙的に return される 明示的な return も書ける メソッド呼び出し時には括弧を省略できる メソッドをキー ワー ドのようにして扱える

Slide 28

Slide 28 text

メソッド名 メソッド名の最後には? , ! , = が使える ? 真偽値を返すメソッド ! , = これから説明

Slide 29

Slide 29 text

bang method s t r = ' f o o ' s t r . u p c a s e # = > ' F O O ' s t r # = > ' f o o ' s t r . u p c a s e ! s t r # = > ' F O O ' 同じ名前のメソッドで 破壊的なものとそうでないものがあるとき、 破壊的な方に! を付ける習慣 破壊的 : 元のオブジェクトを変えてしまう C++ 的に言えば non‑const

Slide 30

Slide 30 text

代入メソッド c l a s s L a b e l d e f t e x t @ t e x t e n d d e f t e x t = ( t ) @ t e x t = t e n d e n d L a b e l . n e w . t e x t = ' f o o ' メソッドの名前の最後に= をつけると オブジェクトのフィー ルドへの代入を 表せるようになる メソッド呼び出しの括弧の省略とあわせると setter / getter を綺麗に書ける

Slide 31

Slide 31 text

Splat d e f f o o ( * a r g s ) a r g s e n d f o o ( 1 , 2 , 3 ) # = > [ 1 , 2 , 3 ] f o o ( * [ 1 , 2 , 3 ] ) # 同じ * を仮引数名につけると 引数が配列にまとめられる * を実引数につけると 配列が展開されて引数になる

Slide 32

Slide 32 text

クラスとモジュー ル

Slide 33

Slide 33 text

クラス Ruby のクラスは単一継承のみ インスタンス変数 @ をつける インスタンス外からはアクセス出来ない s e l f C++ のt h i s 省略可能 c l a s s P u s h B u t t o n < B u t t o n d e f i n i t i a l i z e ( b u t t o n _ f i e l d , n a m e , p u s h e d ) @ n a m e = n a m e b u t t o n _ f i e l d . a d d ( s e l f ) p u s h i f p u s h e d # s e l f . p u s h i f p u s h e d と同じ e n d d e f p u s h @ p u s h e d = t r u e e n d e n d

Slide 34

Slide 34 text

new と initialize b u t t o n = P u s h B u t t o n . n e w ( f i e l d , ' p r e s s m e ' , f a l s e ) インスタンスを作る際は、 n e w というクラスメソッドを呼ぶ i n i t i a l i z e は インスタンスが作られた時に呼ばれるメソッド n e w に渡された引数がそのまま渡される C++ でいうコンストラクタ

Slide 35

Slide 35 text

  モジュー ル m o d u l e M d e f m o d u l e _ m e t h o d ' m e t h o d o f M ' e n d e n d c l a s s C i n c l u d e M e n d c = C . n e w c . m o d u l e _ m e t h o d # = > ' m e t h o d o f M ' クラスとよく似ているが、 インスタンスを作れない 他のクラスまたはモジュー ルから include して 機能の付加 (mixin) のために使う クラスは 1 つしか継承できないが モジュー ルは複数 include できる ( 多重継承 ) CRTP

Slide 36

Slide 36 text

特異メソッド s t r = ' h o g e ' d e f s t r . h o g e ? s e l f = = ' h o g e ' e n d s t r . h o g e ? # = > t r u e クラスやモジュー ルに対してだけではなく オブジェクト単体にもメソッドを定義できる 特異メソッド オブジェクトに対して特異クラスが作られ 特異メソッドはそこに定義される 動的型付き言語らしい機能

Slide 37

Slide 37 text

クラスメソッド c l a s s F o o d e f s e l f . f o o ' f o o ' e n d e n d F o o . f o o # = > ' f o o ' C++ の static メンバ関数と同様な機能 Foo クラス ( s e l f ) の特異メソッドとして定義される 不思議な記法なのはそのため

Slide 38

Slide 38 text

クラスメソッドと インスタンスメソッドの表記法 c l a s s F o o # F o o # f o o d e f f o o e n d # F o o . b a r d e f s e l f . b a r e n d e n d インスタンスメソッドは# クラスメソッドは. を付けて 表記されることが多い

Slide 39

Slide 39 text

Class, Module クラス Ruby ではクラスもモジュー ルも普通のオブジェクト 実行時にも操作できる C++ の型はオブジェクトではなく テンプレー トメタプログラミングでないと 操作できないのと対照的

Slide 40

Slide 40 text

クラス定義中のコー ド実行 c l a s s F o o p u t s ' d e f i n i n g F o o ' a t t r _ a c c e s s o r : h o g e # h o g e , h o g e = が定義される e n d クラス・ モジュー ル定義中には 普通にコー ドを実行できる Class/Module クラスの便利なメソッドも呼べる a t t r _ a c c e s s o r インスタンス変数の setter, getter を定義してくれる

Slide 41

Slide 41 text

ブロック

Slide 42

Slide 42 text

ブロック d e f f o o y i e l d ' f o o ' e n d f o o d o | s t r | p u t s s t r e n d # ' f o o ' と表示される f o o { | s t r | p u t s s t r } # ' b a r ' と表示される メソッドに対して引数とは別に渡される ラムダ式 ( 無名関数 ) にあたるもの do∼end, {∼} で囲む {∼} は一行の時によく使われる y i e l d で呼び出す

Slide 43

Slide 43 text

ブロック d e f b a r ( & b l o c k ) b l o c k . c l a s s # = > P r o c b l o c k . c a l l ' b a r ' e n d 引数名に& を付けると引数として受け取れる P r o c クラスのオブジェクトになる

Slide 44

Slide 44 text

Proc 手続き (procedure) を格納したオブジェクト C++ でいう関数オブジェクト ブロックからp r o c メソッドで作れる & を付けてメソッドに渡すとブロック代わりになる p r c = p r o c { | s t r | p u t s s t r } p r c . c l a s s # = > P r o c p r c . c a l l ( ' h o g e ' ) # ' h o g e ' f o o ( & p r c ) # ' f o o '

Slide 45

Slide 45 text

ブロックを使うメソッド ブロックは構文のような見た目かつ汎用的なので Ruby の様々 な場所に用いられる

Slide 46

Slide 46 text

# e a c h メソッド Array 、Hash などが持つ 要素1つずつに対して処理を行うメソッド Ruby では for 文の代わりの# e a c h が主に使われる C++ ならs t d : : f o r _ e a c h a r y = [ 1 , 2 , 3 ] a r y . e a c h d o | i | p u t s i e n d

Slide 47

Slide 47 text

Enumerable コンテナを一般的に扱うモジュー ル Array 、Hash などが include している C++ の STL アルゴリズムのような機能を提供する # e a c h メソッドを元に機能が実装されている Ruby の# e a c h ≒ C++ のb e g i n ( ) , e n d ( ) ブロックを使った関数型プログラミング a r y = [ 1 , 2 , 3 ] a r y . e a c h d o | i | p u t s i e n d a r y . m a p { | i | i * 2 } # = > [ 2 , 4 , 6 ] a r y . s e l e c t { | i | i . e v e n ? } # = > [ 2 ]

Slide 48

Slide 48 text

I n t e g e r # t i m e s 回数の決まった繰り返しを簡単に表せる 1 0 . t i m e s d o p u t s ' h o g e h o g e ' e n d

Slide 49

Slide 49 text

例外

Slide 50

Slide 50 text

例外 b e g i n f i l e = F i l e . o p e n ( ' s o m e _ f i l e ' ) # エラー があった時 r a i s e ' e r r o r ' r e s c u e p u t s ' e r r o r o c c u r e d ' e n s u r e f i l e . c l o s e e n d

Slide 51

Slide 51 text

例外 r a i s e キー ワー ドで例外を発生させる begin C++ の try rescue C++ の catch ensure 成功・ 失敗どちらにしても行う処理 Java, C# などの finally C++ だと代わりに RAII

Slide 52

Slide 52 text

ブロックを使った RAII っぽい機能 F i l e . o p e n ( ' s o m e _ f i l e ' ) d o | f i l e | # 処理 e n d F i l e . o p e n メソッド ファイルを開いた後、 受け取ったブロックを実行 例外の発生有無にかかわらず 最後にファイルを閉じる スコー プを抜けると自動的にリソー スが閉じられる RAII と共通している

Slide 53

Slide 53 text

メタプログラミング

Slide 54

Slide 54 text

メタプログラミングとは? C++ 、Ruby どちらもメタプログラミングが有名 プログラムに関するプログラム コー ドを生成するプログラム クラス・ メソッドなどのメタなものに対する処理

Slide 55

Slide 55 text

クラス・ メソッドの取得 クラスやメソッドは動的に取得することができる リフレクション s t r = ' s t r ' s t r . c l a s s # = > S t r i n g s t r . m e t h o d s # = > インスタンスメソッドのリスト ( 特異メソッド含む) S t r i n g . i n s t a n c e _ m e t h o d s # = > S t r i n g のインスタンスメソッドのリスト S t r i n g . m e t h o d s # = > S t r i n g のクラスメソッドのリスト

Slide 56

Slide 56 text

クラス・ メソッドの取得 C++ で変数から型を取得 d e c l t y p e C++ にはメソッド一覧を取得する機能はない 最近、C++ 標準化委員会では リフレクションに関する議論がなされている そのうち入るかも?

Slide 57

Slide 57 text

Method, UnboundMethod m = 1 . m e t h o d ( : e v e n ? ) m . c l a s s # = > M e t h o d m . c a l l # = > f a l s e u = I n t e g e r . i n s t a n c e _ m e t h o d ( : e v e n ? ) u . c l a s s # = > U n b o u n d M e t h o d u . b i n d ( 2 ) . c a l l # = > t r u e Method オブジェクト オブジェクトと関連付けられている Proc とよく似ている C++ だと、std::bind で束縛されたメンバ関数 UnboundMethod オブジェクト オブジェクトと関連付けられていない # b i n d で関連付けて Method に C++ だと、 メンバ関数ポインタ

Slide 58

Slide 58 text

メソッドの動的定義 c l a s s F o o [ : h o g e , : p i y o ] . e a c h d o | m e t h | d e f i n e _ m e t h o d m e t h d o m e t h e n d e n d e n d f = F o o . n e w f . h o g e # = > : h o g e d e f i n e _ m e t h o d メソッド名とブロックを与えて メソッドを動的に定義

Slide 59

Slide 59 text

method̲missing c l a s s F o o d e f m e t h o d _ m i s s i n g ( n a m e , * a r g s , & b l o c k ) p u t s " m i s s i n g m e t h o d # { n a m e } " e n d e n d F o o . n e w . n o _ s u c h _ m e t h o d # m i s s i n g m e t h o d n o _ s u c h _ m e t h o d と表示される メソッドが見つからなかった時に呼ばれる デフォルトの挙動では NoMethodError を投げる

Slide 60

Slide 60 text

method̲missing 例 : 標準ライブラリの OpenStruct r e q u i r e ' o s t r u c t ' s = O p e n S t r u c t . n e w s . m e t h o d s . g r e p ( / h o g e / ) # = > [ ] s . h o g e = ' h o g e ' s . m e t h o d s . g r e p ( / h o g e / ) # = > [ : h o g e , : h o g e = ] d e f i n e _ m e t h o d と組み合わせて 動的に新しいメソッドを定義可能 ORM (SQL などをラップするしくみ ) でも よく使われる ActiveRecord など

Slide 61

Slide 61 text

eval 文字列を実行 ( 評価 ) n = 1 0 e v a l ( ' n * 2 ' ) # = > 2 0

Slide 62

Slide 62 text

instance̲eval ブロックをそのオブジェクトの インスタンスメソッドと同じ文脈で実行 具体的に言うと、self がそのオブジェクトになる

Slide 63

Slide 63 text

instance̲eval c l a s s C a l c u l a t o r d e f i n i t i a l i z e @ v a l u e = 0 e n d d e f a d d ( x ) @ v a l u e + = x e n d e n d C a l c u l a t o r . n e w . i n s t a n c e _ e v a l d o a d d 2 a d d 1 0 p u t s @ v a l u e # 1 2 e n d このような DSL 風のコー ドを書くこともできるが インスタンス変数にアクセスできてしまうので 欠陥…

Slide 64

Slide 64 text

C++ と Ruby の メタプログラミングの対比 C++ のメタプログラミング プリプロセッサメタプログラミング テンプレー トメタプログラミング constexpr メタプログラミング Ruby のメタプログラミング 実行時メタプログラミング のみ

Slide 65

Slide 65 text

テスト

Slide 66

Slide 66 text

テスト Ruby ではテストがないとつらい 動的言語なので、typo などで実行時エラー になる テストを書けば typo も挙動も同時にチェックできる

Slide 67

Slide 67 text

RSpec Ruby 用の有名なテストフレー ムワー ク 振る舞い駆動開発 BDD 最初に振る舞いを規定するテスト (spec) を書き それに基づいて実装を行うという考え方 d e s c r i b e P e r s o n d o d e s c r i b e ' # g r e e t ' d o i t ' r e t u r n s " H e l l o " ' d o e x p e c t ( P e r s o n . n e w . g r e e t ) . t o e q ( ' H e l l o ' ) e n d e n d e n d テストコー ドであるが Person#greet が' H e l l o ' を返すという 「 仕様」 を規定している

Slide 68

Slide 68 text

RSpec メタプログラミングによる内部 DSL で、 自然言語に近い spec を記述できる

Slide 69

Slide 69 text

まとめ

Slide 70

Slide 70 text

まとめ C++ の視点から見た Ruby の特徴的な機能などを紹介した スクリプト言語らしいゆるい構文 動的性 メタプログラミング DSL など C++ 、 ゲー ムとはあまり関係なかったけど 何らかの参考になれば幸い