Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Ruby 型別檢查工具簡介
Search
Johnlin
July 31, 2022
Programming
0
420
Ruby 型別檢查工具簡介
於 Coscup 2022 發表。
https://johnlin.vc/coscup-2022/
Johnlin
July 31, 2022
Tweet
Share
More Decks by Johnlin
See All by Johnlin
用 MLIR 實作 一個 Ruby IR (intermediate representation)
johnlinvc
0
78
Unearth Ruby builtin Gems 發掘 Ruby 的內建 Gems
johnlinvc
0
220
Swift Actor 實作探索
johnlinvc
0
140
用 mruby 來寫跨平台工具
johnlinvc
0
64
Actor model 簡介
johnlinvc
0
170
一起玩 Helm 3
johnlinvc
1
100
為什麼 App 卡卡的
johnlinvc
2
1.1k
如何使用 byebug 來除錯 Ruby 程式
johnlinvc
0
180
Life of a Cell
johnlinvc
0
1.4k
Other Decks in Programming
See All in Programming
PRレビューのお供にDanger
stoticdev
1
230
PHPカンファレンス名古屋2025 タスク分解の試行錯誤〜レビュー負荷を下げるために〜
soichi
1
680
推しメソッドsource_locationのしくみを探る - はじめてRubyのコードを読んでみた
nobu09
2
300
2025.2.14_Developers Summit 2025_登壇資料
0101unite
0
200
メンテが命: PHPフレームワークのコンテナ化とアップグレード戦略
shunta27
0
300
『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya
o0h
PRO
8
2.4k
Datadog Workflow Automation で圧倒的価値提供
showwin
1
160
責務と認知負荷を整える! 抽象レベルを意識した関心の分離
yahiru
8
1.3k
第3回関東Kaggler会_AtCoderはKaggleの役に立つ
chettub
3
1.2k
もう少しテストを書きたいんじゃ〜 #phpstudy
o0h
PRO
17
4k
データの整合性を保つ非同期処理アーキテクチャパターン / Async Architecture Patterns
mokuo
54
19k
PHPのバージョンアップ時にも役立ったAST
matsuo_atsushi
0
230
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
193
16k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Thoughts on Productivity
jonyablonski
69
4.5k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.1k
GitHub's CSS Performance
jonrohan
1030
460k
The Power of CSS Pseudo Elements
geoffreycrofte
75
5.5k
Building Adaptive Systems
keathley
40
2.4k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
366
25k
Fireside Chat
paigeccino
34
3.2k
Scaling GitHub
holman
459
140k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
46
2.3k
Transcript
Ruby ܕผᒾҰ۩؆հ John Lin (@johnlinvc)
᮫ԙզ • John Lin • تᓣ Ruby & Swiftɻओ㭎Swift Taipei
Meetupɻ • Twitter: @johnlinvc • Blog: https://johnlin.vc/ • Principle Solution Architect @ West Pharmaceutical Service (ࣜဌऱ)
ڧྗ㐸࠽த • ओཁੋ၏ᬭྍᢛۀ IoT ɻूᅶᚙలॏ৺೭Ұɻ • google "cake resume west"ɼ༗ෟࢿൣᅴɻ
• ཤ㑖త࣌㘸ੋ John Lin հతɻိత referral bonus 㟬Ұɻ • Coscup ᩶ॿ
Agenda • Ruby తܕผܥ౷ • ܕผᒾҰత႔ • Ruby ܕผᒾҰ۩తಛ৭ •
Sorbet • Steep • ൺֱ Ruby తܕผᒾҰ۩ • Q&A
Ruby తܕผܥ౷ • ڧܕผ Strong Type • ಈଶܕผ Dynamic Type
• יࢠܕผ Duck typing • ॴ༗౦ੋ݅ Everything is object • ᄸҰঝ Single Inheritance • Mixin • nil
ܕผᒾҰత႔ • ᒾҰଧࣈࡨޡ • ᒾҰჩᏐၚᬇࡨޡ • ఏߴఔࣜᛰతՄᯪੑ • ՄҎॱศఏڙఔࣜᛰతࢿ㘤څ IDEɻ
Ruby ܕผᒾҰ۩తڞಉಛ৭ • ᔒ༗ํతܕผᒾҰ۩ • ਐࣜܕผᒾҰ Gradual type checker. •
ܕผఆٛ䈕 Type def fi les
ᔒ༗ํతܕผᒾҰ۩ • ᔒ༗ํతܕผᒾҰ۩ɻ • ୠੋ༗ํతܕผඪɼRuby Signature (RBS) ɻ • Python
& javascript ੋҰᒬɻ
RBS ܕผఆٛ䈕 • Ruby ํతܕผఆٛ֨ࣜɻ • ᘐཱ䈕Ҋɻ • ՄҎኺݪ࢝ᛰࣗಈ㗞ੜൣຊɻ
ਐࣜܕผᒾҰ Gradual Type Check • ՄҎᒾҰ෦తఔࣜᛰɻ • ߱ಋೖɻ • Python(mypy)
& TypeScript ੋɻ
ܕผఆٛ䈕 • ᘐཱత䈕Ҋɻ • ఆٛྃܕผɼৗᏐɼํ๏ɼݸᱪᏓᏐతܕผɻ • class Foo def bar(s);
end end class Foo def bar: (s: String) -> String end
ܕผᩄ (type annotation) • ࡏఔࣜᛰதՃ্Ḽղ҃ੋֹ֎తඪࣔɻ • ૾ੋ C++, Python ҃
Typescript ੋɻ class Foo sig{params(s: String).returns(String)} def bar(s) end end
ܕผఆٛ䈕త༏᠍ᴍ • ᠍ᴍɿఔࣜܕผఆٛࡏෆಉ䈕ҊɼՄೳ။هվɻ • ༏ᴍɿఔࣜޠ๏ൺֱᄸ७ɻ
None
ܕผఆٛ䈕 V.S. ܕผᩄ (type annotation) • Matz: • ఔࣜෆधཁܕผඪࣔब။ಈɻtype annotation
ҧྃ DRY(Don't Repeat Yourself) ݪଇɻ • ະိՊٕⴺਐ㑊ޙɼ༗Մೳશෆधཁܕผఆٛ䈕ɻ
Ruby ܕผੳ۩ • Sorbet • Steep
Sorbet • ༝ Stripe ։ᚙɼ༻ C++ & Rubyሜతɻ • ᯩଶᒾҰ
ˍ ಈଶᒾҰ • 㚎ݐޠݴثڠఆ(Language Server Protocol, LSP) • ෆಉڃతਐࣜᒾҰ • ಉ࣌ࢧԉ ܕผᩄ(Type Annotation) ᢛ RBI ܕผఆٛ䈕ɻ
ᯩଶᒾҰ • ࣥߦsorbet ိᒾҰܕผɼෆधཁਅతࣥߦఔࣜɻ • ༻ڥɿሜఔࣜதɼ lsp serverɻ࿈᠃߹(CI)ɻ
ಈଶᒾҰ • ࣥߦఔࣜత࣌ީɼSorbet ။ᒾҰܕผฒ㗞ੜࡨޡ҃Log • ༻ڥɿ࿈᠃߹(CI)தతᄸݩଌࢼ҃߹ଌࢼɻ༬උ ڥ(Staging)ɻਖ਼ࣜڥɻ
㚎ݐޠݴثڠఆ • VSCode ҃ Emacs ࢧԉ ޠݴثڠఆ తฤाث ࣌ɼՄҎଈ࣌ᰖࣔࡨޡɻෆधཁ㠥֎ࣥߦࢦྩɻ
• ఏڙྃ౸ఆٛɼᰖࣔ༻ᴍɼᏓᏐվ໊ޭೳɻ
ෆಉڃతਐࣜᒾҰ • ࡏ䈕Ҋ։಄Ճ্ਆحḼղ # typed: LEVEL बՄҎઃఆᒾҰతڃ • # typed:
ignore : શࠌུɼՄҎෆੋ༗Ꮘతఔࣜᛰ • # typed: false ɿ ᒾҰޠ๏ɼ༬ઃᆴɻ • # typed: trueɿᒾҰ༗ఆٛతܕผɼ • # typed: strict :ॴ༗తܕผधཁ༗ఆٛɻ • # typed: strongɿbug ଟɼෆཁ༻ɻ
Sorbet ܕผඪࣔ • ՄҎࡏఔࣜᛰத၏ܕผᩄ • ՄҎ༻ᘐཱత RBI ܕผఆٛ䈕 • ՄҎಉ࣌༻ɻୠੋෆೳॏෳඪࣔɻ
ܕผᩄ • ༻ T:Sig module ိ၏ܕผᩄɻ • ܕผᩄޙతఔࣜᛰґવੋ߹๏త Ruby ఔࣜᛰɻ
• ՄҎሣᏓᏐ၏ܕผᩄɻ extend T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); n+1; end
RBI ܕผఆٛ䈕 • ܕผᩄաޙతఔࣜ፤ᎃመ࡞ɼबྃ RBI ܕผఆٛ 䈕ɻ • ೳሣৗᏐɼํ๏መᱪᏓᏐ၏ܕผඪࣔɻ extend
T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); end def add1(n) n+1 end
جຊܕผ • T.untyped • Ұൠܕผ • Boolean • Array &
Hash • Nilable • Block & Proc & lambda
T.untyped • ᔒ༗څܕผ࣌ީత typeɻ • BasicObject ʢॴ༗݅తڞಉઌʣ ෆಉɼT.untyped ။શུաܕผᒾҰɻ
• T.untyped => զෆࡏݷ • BasicObject => զෆಓɻ
Ұൠܕผ • 1 => Integer or Numeric • 3.14 =>
Float or Numeric • "hello" => String • :world => Symbol
Boolean • true => T::Boolean or TrueClass • false =>
T::Boolean or FalseClass • T::Boolean => Union(TrueClass ,FalseClass)
Array & Hash • [1,2,3] => T::Array[Integer] • %w{a b
c} => T::Array[String] • {hello: "world"} => T::Hash[Symbol, String] • {"answer" => 42} => T::Hash[String, Integer]
T.nilable • T.nilable(Integer) => Union(NilClass, Integer) • ENV["RAILS_ENV"] => T.nilable(String)
• debug = T.must(ENV["DEBUG"]) => String Ռ DEBUG ෆଘࡏɼࣥߦظ။㋝ग़ྫ֎ • debug = ENV.fetch("DEBUG","") => String
Block & Proc & lambda • proc {|n| n *
2 } => T.proc.params(n: Integer).returns(Integer) • Proc.new{|n| n*2} => Proc
ಛघܕผ • ࿆ूܕผ T.any • ަूܕผ T.all
࿆ूܕผ T.any • ՄҎҝଖதҰछܕผ • T.nilable(X) => T.any(NilClass, X) sig
{params(x: T.any(Integer,String)).void} def foo(x); end foo(10) foo("Hello, world")
ަूܕผ T.all • ಉ࣌༗ Module1 & Module2 ၷݸ Mixin •
{params(x: T.all(Module1, Module2)).void} def requires_both(x) x.method1 # ok x.method2 # also ok end
ํ๏ܕผඪࣔ • ҰൠჩᏐ & ᮫伴ࣈჩᏐ • ՄᏓჩᏐ • block ჩᏐ
• Void ճၚᆴ
ҰൠჩᏐ & ᮫伴ࣈჩᏐ extend T::Sig sig{params(n: Integer, s: String).returns(String)} def
foo(n) "#{n} #{s}" end
ՄᏓჩᏐ • args ҰఆੋArray ॴҎཁඪࣔݩૉతܕผ • kwargs Ұఆੋ Keyҝ Symbol
త Hash, ॴҎཁඪࣔValue తܕผɻ extend T::Sig sig{params(args: Int, kwargs: String).returns(String)} def foo(*args, **kwargs) "#{args.sum}" + kwargs.map{|k,v| "#{k}: #{v}"} end
block ჩᏐ • ཁՃ &blk ࠽ೳඪࣔჩᏐతܕผɻᔒՃత block ။ඃᙛ untyped sig
{params(blk: T.proc.returns(Integer)).returns(Integer)} def foo(&blk) # <- yield end
Void ճၚᆴ • Ruby Ӭԕ။ճၚ࠷ޙҰߦɻୠ༗࣌ީੋ䭘䭓ᆴɻ • ඪ্ void తबՄҎආ໔ޡ༻ճၚᆴɻ sig
{params(name: String).void} def greet(name) puts "Hello, #{name}!" end puts greet("Coscup") # ERROR !
ᏓᏐܕผඪࣔ • T.let • T.cast • T.bind
T.let • ઃఆᏓᏐత type • ෆ߹ཧత value ။༗ errorɻ x
= T.let(10, Integer) y = T.let(10, String) # error
T.cast • ՄҎڧ੍ܕଖଞ typeɻ • ୠؐੋ။ᒾҰ A ౸ఈ༗ᔒ༗ foo ํ๏ɻ
case label when 'a' T.cast(a_or_b, A).foo when 'b' T.cast(a_or_b, B).bar end
T.bind • self ڧ੍ܕ༻త • self ෆೳ༻ T.cast •
ࡏ proc/block ཫ໘۰౸ instance_eval ࣌መ༻ T.bind(self, MyClass) self.method_on_my_class
fl ow-sensitive • Sorbet ಓࡏ if ཫ໘త x ෆՄೳੋ nilɼॴҎෆ။༗ܕผࡨ
ޡɻ • if/unless, case, nil? , is_a? , ! , &&, || ။աᖤᎃෆՄೳత ܕผ x = T.let(1, T.nilable(Integer)) if x x + 1 # No Error end
আࡨޭೳ • ՄҎ༻ိᰖࣔҰݸᆴ༬ظతܕผɻ • Ұ։࢝ෆಓܕผత࣌ީ༻ɻ T.reveal_type(1) editor.rb:9: Revealed type: Integer(1)
https://srb.help/7014
T.unsafe • զಓࣗݾࡏ၏ॄኄɻผզɻ class A def method_missing(method) puts "Called #{method}"
end end T.unsafe(A.new).foo # => ok
ਐ֊ܕผఆٛ • Abstract class & interface • Sealed class •
Final class
ҏἾ֥ূ • ࣥߦ༻త script ཁ༻ if __FILE__ == $PROGRAM_NAME แىိɻ
• RSpec ။༗Ұେථ TypeErrorɻՄҎશ෦ ignoreɻ • ଟ Gem ؐᔒ༗ Type De fi nitionɻ၏ग़։ݯߩᘔతେ ࣌ػɻ
Steep • by Soutaro Matsumoto ɼ༻ Ruby ሜతɻ • ํతܕผᒾҰثɼʢҼҝ
RBS ੋಉҰݸ࡞ऀʣ • ᯩଶᒾҰɻ • ༻ ᘐཱత RBS ܕผఆٛ䈕ɻ • gem install steep
Steep fi le target :app do check "lib" signature "sig"
library "set", "pathname" end
Steep తਐࣜᒾҰ • ۰౸ᔒ༗ܕผᩄతఔࣜᛰɼ။ᙛ࡞ untyped ိ႔ཧɻ • untyped త݅။աॴ༗తᒾҰɻ •
༗ෆᒾҰత䈕ҊՄҎࡏ Steep fi le ཫ ignore ᎃɻ
RBS ܕผఆٛ䈕 class Channel attr_reader name: String def initialize: (name:
String) -> void def each_member: () { (User | Bot) -> void } -> void # `{` and `}` means block. | () -> Enumerator[User | Bot, void] # Method can be overloaded. end
RBI vs RBS • RBI: ෆՄҎఆٛ typeɼؐՄҎሣܕผ၏ਐ֊ఆٛɻ • RBS: ՄҎ၏
overloading • መࡍ্બ䬟ݸՄҎɼ༗۩(parlour) ՄҎ၏ɻ
֘༻䬟Ұݸʁ • Sorbet • ൺֱख़ɼࣕ Stripe ࣗݾ༗ࡏ༻ɻ
݁ • Ruby ܕผᒾҰثਖ਼ࡏᚙలதɻ • Sorbet ੋલൺֱख़తᒾҰثɻ • ݱࡏੋሣ Ruby
ܕผᒾҰ࡞ग़ߩᘔతେ࣌ػɻ
Q&A • Өยࡏ https://johnlin.vc/ coscup-2022/ • ՄҎࡏ twitter ্ፙ౸զ @johnlinvc
• ༗ڵझՄҎగ㕕զత blog https://johnlin.vc
References • https://sorbet.org • https://github.com/soutaro/steep • https://www.youtube.com/watch?v=2g9R7PUCEXo • https://www.thestrangeloop.com/2019/typing-the- untyped-soundness-in-gradual-type-systems.html
• [2] https://github.com/AaronC81/parlour