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
510
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
180
Unearth Ruby builtin Gems 發掘 Ruby 的內建 Gems
johnlinvc
0
290
Swift Actor 實作探索
johnlinvc
0
170
用 mruby 來寫跨平台工具
johnlinvc
0
87
Actor model 簡介
johnlinvc
0
200
一起玩 Helm 3
johnlinvc
1
130
為什麼 App 卡卡的
johnlinvc
2
1.2k
如何使用 byebug 來除錯 Ruby 程式
johnlinvc
0
220
Life of a Cell
johnlinvc
0
1.4k
Other Decks in Programming
See All in Programming
Java_プロセスのメモリ監視の落とし穴_NMT_で見抜けない_glibc_キャッシュ問題_.pdf
ntt_dsol_java
0
170
Verilator + Rust + gRPC と Efinix の RISC-V でAIアクセラレータをAIで作ってる話 RTLを語る会(18) 2025/11/08
ryuz88
0
360
知られているようで知られていない JavaScriptの仕様 4選
syumai
0
590
Functional Calisthenics in Kotlin: Kotlinで「関数型エクササイズ」を実践しよう
lagenorhynque
0
130
AI 時代だからこそ抑えたい「価値のある」PHP ユニットテストを書く技術 #phpconfuk / phpcon-fukuoka-2025
shogogg
1
430
2026年向け会社紹介資料
misu
0
170
高単価案件で働くための心構え
nullnull
0
130
Swift Concurrency 年表クイズ
omochi
3
230
PyCon mini 東海 2025「個人ではじめるマルチAIエージェント入門 〜LangChain × LangGraphでアイデアを形にするステップ〜」
komofr
3
960
乱雑なコードの整理から学ぶ設計の初歩
masuda220
PRO
31
12k
CSC509 Lecture 13
javiergs
PRO
0
250
FlutterKaigi 2025 システム裏側
yumnumm
0
1k
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
54
7.9k
Producing Creativity
orderedlist
PRO
348
40k
Optimizing for Happiness
mojombo
379
70k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
658
61k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Why Our Code Smells
bkeepers
PRO
340
57k
Done Done
chrislema
186
16k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
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