Upgrade to Pro — share decks privately, control downloads, hide ads and more …

動的型解析器 Ethotrace

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

動的型解析器 Ethotrace

Avatar for すぎうり

すぎうり

June 23, 2026

More Decks by すぎうり

Other Decks in Programming

Transcript

  1. 自己紹介 すぎうり • Twitter:@uproad3 • Ruby歴20年 • VRChat歴7年 • 仕事:Rails |

    AWS | LT芸人 • 趣味:アーキテクト | リファクタリング | 電子工作 • 言語:Ruby | C# | C | JS | ほかいろいろ • 技術:Terraform | Unity | Ubuntu | MySQL | RaspberryPi • 悲しきフルスタックエンジニア • 最近はClaudeをシバきまわしている • 特に型に強い思い入れがあるわけではない
  2. 第1章 型注釈 強制されてませんか ? TypeScript / Java / C# /

    Rust … 型を書かないとコンパイルが通らない Rubyには、それがない。 ——自由だ。
  3. 第1章 Rubyには型注釈がない=自由 型注釈を書かなくていい。書いてすぐ動く。 ダックタイピング ——「each できれば何でもいい」 # 型注釈なしでも動く def process(items)

    items.each { |x| puts x } end process([1, 2, 3]) # OK process("hello") # OK (each を持てば何でも) この自由さがRubyの良さ——でも、代償がある
  4. 第1章 でも、その自由の代償に —— def process(x) String Array Enumable IO 結局

    何を渡せばいいのか? 何が返ってくるのか? 型注釈もドキュメントもない。 コードを上から下まで追うしかない。 String Array
  5. 第1章 見えないものは、 3つある def process(x) ① 引数 何を渡せばいい? ② 投げる例外

    何がraiseしうる? ③ 外部依存 裏で何に触ってる? インターフェースが見えないから ——使い方がわからない ④ 戻り値 何が返ってくる?
  6. 第1章 "書けば"解決する。でも —— 型注釈を書けば解決する # sig { params(x: T.untyped) #

    .returns(String) } def process(x) ... end RBS / Sorbet でも—— ・書くコストが高い ・既存コードへの後付けは重い ・メタプロと相性が悪い 書かずに、型情報を手に入れる方法はないか ? ——テストがすでに証拠を持っている
  7. 2章 型は"書く"のではなく "観測する" 「書く」 RBS / Sorbet 人がコードを読んで宣言する 書くコストがかかる 後付けは重い 書くコストなしには型情報が得られない

    「観測する」 ethotrace テストを走らせて記録する 書かなくていい テストがあれば証拠はある テストを走らせるだけで型情報が手に入る
  8. 第2章 型には、3つの側面がある Effect-TS の Effect<Success, Error, Requirements> という捉え方を借りた (詳しいのはそのへんにいるんで後で聞いてください) Success

    成功して何を返すか Error どんな失敗をしうるか Requirements 何を必要とするか 型は「引数」と「戻り値」だけじゃない ——テストで観測すればこの 3つが採れる
  9. 第3章 prepend で、メソッド呼び出しを捕まえる module ArgumentTracer def process(x) # 引数に呼ばれたメソッドを記録 called

    = detect_protocol(x) # x に何が呼ばれるか観測 $observations << { method: :process, args_protocol: called } super # 元のメソッドを呼ぶ end end MyClass.prepend(ArgumentTracer) 詳しくはリポジトリで: github.com/uproad/ethotrace
  10. 第3章 観測結果——引数プロトコル 整形後の観測結果(実際の出力を読みやすく表示) method: MyClass#process args: x → protocol: [:each,

    :map, :size] # xに呼ばれたメソッドの集合 # = "each、map、sizeを持っていれば何でも渡せる " 「型名」ではなく「呼ばれたメソッド集合」 ——これがダックタイピングの型の実体
  11. 第3章 このメソッドは例外を投げうるか prepend の rescue で、外に飛んだ例外を捕まえる module ExceptionTracer def process(x)

    super rescue => e # 外に飛んだ例外クラスを記録 $observations << { raised: e.class } raise # 再度投げる end end 「型注釈には載らない情報」 ——呼び出し元が何を rescueすべきか、観測が教えてくれる
  12. 第3章 観測結果——例外チャネル method: MyClass#process raised: - ArgumentError - Tax::RateError #

    このメソッドはこれらを投げ "うる" 型注釈には普通載らない情報。 でも、呼び出し元はこれを知りたい ——何を rescue すべきかが分かる
  13. 第3章 もうひとつ ——外部依存も見える method: MyClass#process requirements: - time.read # Time.now

    を呼んだ - env.read(KEY) # ENV['KEY'] を参照した # requirements が空 = 純粋なメソッド ENV・Time・IO に触れたか——「純粋かどうか」が分かる