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
450
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
110
Unearth Ruby builtin Gems 發掘 Ruby 的內建 Gems
johnlinvc
0
240
Swift Actor 實作探索
johnlinvc
0
150
用 mruby 來寫跨平台工具
johnlinvc
0
71
Actor model 簡介
johnlinvc
0
180
一起玩 Helm 3
johnlinvc
1
110
為什麼 App 卡卡的
johnlinvc
2
1.1k
如何使用 byebug 來除錯 Ruby 程式
johnlinvc
0
200
Life of a Cell
johnlinvc
0
1.4k
Other Decks in Programming
See All in Programming
イベントソーシングとAIの親和性ー物語とLLMに理解できるデータ
tomohisa
0
120
rbs-traceを使ってWEARで型生成を試してみた After RubyKaigi 2025〜ZOZO、ファインディ、ピクシブ〜 / tried rbs-trace on WEAR
oyamakei
0
140
Cursor/Devin全社導入の理想と現実
saitoryc
29
22k
インプロセスQAにおいて大事にしていること / In-process QA Meetup
medley
0
190
20250426 GDGoC 合同新歓 - GDGoC のススメ
getty708
0
120
医療系ソフトウェアのAI駆動開発
koukimiura
1
140
Beyond_the_Prompt__Evaluating__Testing__and_Securing_LLM_Applications.pdf
meteatamel
0
120
ASP.NETアプリケーションのモダナイゼーションについて
tomokusaba
0
280
eBPF超入門「o11yに使える」とは (20250424_eBPF_o11y)
thousanda
1
120
開発者フレンドリーで顧客も満足?Platformの秘密
algoartis
0
250
生成AI時代のフルスタック開発
kenn
8
1k
OpenTelemetryで始めるベンダーフリーなobservability / Vendor-free observability starting with OpenTelemetry
seike460
0
130
Featured
See All Featured
Statistics for Hackers
jakevdp
799
220k
The Pragmatic Product Professional
lauravandoore
33
6.6k
Unsuck your backbone
ammeep
671
58k
Designing for humans not robots
tammielis
253
25k
How to Think Like a Performance Engineer
csswizardry
23
1.6k
Embracing the Ebb and Flow
colly
85
4.7k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.5k
Done Done
chrislema
184
16k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
5
620
Documentation Writing (for coders)
carmenintech
71
4.8k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
3.8k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.7k
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