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
460
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
130
Unearth Ruby builtin Gems 發掘 Ruby 的內建 Gems
johnlinvc
0
260
Swift Actor 實作探索
johnlinvc
0
160
用 mruby 來寫跨平台工具
johnlinvc
0
77
Actor model 簡介
johnlinvc
0
190
一起玩 Helm 3
johnlinvc
1
120
為什麼 App 卡卡的
johnlinvc
2
1.2k
如何使用 byebug 來除錯 Ruby 程式
johnlinvc
0
200
Life of a Cell
johnlinvc
0
1.4k
Other Decks in Programming
See All in Programming
CDK引数設計道場100本ノック
badmintoncryer
2
360
ニーリーにおけるプロダクトエンジニア
nealle
0
890
PHPで始める振る舞い駆動開発(Behaviour-Driven Development)
ohmori_yusuke
2
420
Deep Dive into ~/.claude/projects
hiragram
14
11k
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
2
650
Rubyでやりたい駆動開発 / Ruby driven development
chobishiba
1
750
チームのテスト力を総合的に鍛えて品質、スピード、レジリエンスを共立させる/Testing approach that improves quality, speed, and resilience
goyoki
5
1k
レベル1の開発生産性向上に取り組む − 日々の作業の効率化・自動化を通じた改善活動
kesoji
0
270
スタートアップの急成長を支えるプラットフォームエンジニアリングと組織戦略
sutochin26
1
6.7k
20250628_非エンジニアがバイブコーディングしてみた
ponponmikankan
0
710
NEWT Backend Evolution
xpromx
1
110
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
330
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
328
39k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
5.9k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
8
830
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
50
5.5k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
107
19k
Git: the NoSQL Database
bkeepers
PRO
430
65k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Making the Leap to Tech Lead
cromwellryan
134
9.4k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
8
700
Raft: Consensus for Rubyists
vanstee
140
7k
We Have a Design System, Now What?
morganepeng
53
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