Ruby 型別檢查工具簡介
by
Johnlin
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
Ruby ܕผᒾҰ۩؆հ John Lin (@johnlinvc)
Slide 2
Slide 2 text
᮫ԙզ • John Lin • تᓣ Ruby & Swiftɻओ㭎Swift Taipei Meetupɻ • Twitter: @johnlinvc • Blog: https://johnlin.vc/ • Principle Solution Architect @ West Pharmaceutical Service (ࣜဌऱ)
Slide 3
Slide 3 text
ڧྗ㐸࠽த • ओཁੋ၏ᬭྍᢛۀ IoT ɻूᅶᚙలॏ৺೭Ұɻ • google "cake resume west"ɼ༗ෟࢿൣᅴɻ • ཤ㑖త࣌㘸ੋ John Lin հతɻိత referral bonus 㟬Ұɻ • Coscup ᩶ॿ
Slide 4
Slide 4 text
Agenda • Ruby తܕผܥ౷ • ܕผᒾҰత႔ • Ruby ܕผᒾҰ۩తಛ৭ • Sorbet • Steep • ൺֱ Ruby తܕผᒾҰ۩ • Q&A
Slide 5
Slide 5 text
Ruby తܕผܥ౷ • ڧܕผ Strong Type • ಈଶܕผ Dynamic Type • יࢠܕผ Duck typing • ॴ༗౦ੋ݅ Everything is object • ᄸҰঝ Single Inheritance • Mixin • nil
Slide 6
Slide 6 text
ܕผᒾҰత႔ • ᒾҰଧࣈࡨޡ • ᒾҰჩᏐၚᬇࡨޡ • ఏߴఔࣜᛰతՄᯪੑ • ՄҎॱศఏڙఔࣜᛰతࢿ㘤څ IDEɻ
Slide 7
Slide 7 text
Ruby ܕผᒾҰ۩తڞಉಛ৭ • ᔒ༗ํతܕผᒾҰ۩ • ਐࣜܕผᒾҰ Gradual type checker. • ܕผఆٛ䈕 Type def fi les
Slide 8
Slide 8 text
ᔒ༗ํతܕผᒾҰ۩ • ᔒ༗ํతܕผᒾҰ۩ɻ • ୠੋ༗ํతܕผඪɼRuby Signature (RBS) ɻ • Python & javascript ੋҰᒬɻ
Slide 9
Slide 9 text
RBS ܕผఆٛ䈕 • Ruby ํతܕผఆٛ֨ࣜɻ • ᘐཱ䈕Ҋɻ • ՄҎኺݪ࢝ᛰࣗಈ㗞ੜൣຊɻ
Slide 10
Slide 10 text
ਐࣜܕผᒾҰ Gradual Type Check • ՄҎᒾҰ෦తఔࣜᛰɻ • ߱ಋೖɻ • Python(mypy) & TypeScript ੋɻ
Slide 11
Slide 11 text
ܕผఆٛ䈕 • ᘐཱత䈕Ҋɻ • ఆٛྃܕผɼৗᏐɼํ๏ɼݸᱪᏓᏐతܕผɻ • class Foo def bar(s); end end class Foo def bar: (s: String) -> String end
Slide 12
Slide 12 text
ܕผᩄ (type annotation) • ࡏఔࣜᛰதՃ্Ḽղ҃ੋֹ֎తඪࣔɻ • ૾ੋ C++, Python ҃ Typescript ੋɻ class Foo sig{params(s: String).returns(String)} def bar(s) end end
Slide 13
Slide 13 text
ܕผఆٛ䈕త༏᠍ᴍ • ᠍ᴍɿఔࣜܕผఆٛࡏෆಉ䈕ҊɼՄೳ။هվɻ • ༏ᴍɿఔࣜޠ๏ൺֱᄸ७ɻ
Slide 14
Slide 14 text
No content
Slide 15
Slide 15 text
ܕผఆٛ䈕 V.S. ܕผᩄ (type annotation) • Matz: • ఔࣜෆधཁܕผඪࣔब။ಈɻtype annotation ҧྃ DRY(Don't Repeat Yourself) ݪଇɻ • ະိՊٕⴺਐ㑊ޙɼ༗Մೳશෆधཁܕผఆٛ䈕ɻ
Slide 16
Slide 16 text
Ruby ܕผੳ۩ • Sorbet • Steep
Slide 17
Slide 17 text
Sorbet • ༝ Stripe ։ᚙɼ༻ C++ & Rubyሜతɻ • ᯩଶᒾҰ ˍ ಈଶᒾҰ • 㚎ݐޠݴثڠఆ(Language Server Protocol, LSP) • ෆಉڃతਐࣜᒾҰ • ಉ࣌ࢧԉ ܕผᩄ(Type Annotation) ᢛ RBI ܕผఆٛ䈕ɻ
Slide 18
Slide 18 text
ᯩଶᒾҰ • ࣥߦsorbet ိᒾҰܕผɼෆधཁਅతࣥߦఔࣜɻ • ༻ڥɿሜఔࣜதɼ lsp serverɻ࿈᠃߹(CI)ɻ
Slide 19
Slide 19 text
ಈଶᒾҰ • ࣥߦఔࣜత࣌ީɼSorbet ။ᒾҰܕผฒ㗞ੜࡨޡ҃Log • ༻ڥɿ࿈᠃߹(CI)தతᄸݩଌࢼ҃߹ଌࢼɻ༬උ ڥ(Staging)ɻਖ਼ࣜڥɻ
Slide 20
Slide 20 text
㚎ݐޠݴثڠఆ • VSCode ҃ Emacs ࢧԉ ޠݴثڠఆ తฤाث ࣌ɼՄҎଈ࣌ᰖࣔࡨޡɻෆधཁ㠥֎ࣥߦࢦྩɻ • ఏڙྃ౸ఆٛɼᰖࣔ༻ᴍɼᏓᏐվ໊ޭೳɻ
Slide 21
Slide 21 text
ෆಉڃతਐࣜᒾҰ • ࡏ䈕Ҋ։಄Ճ্ਆحḼղ # typed: LEVEL बՄҎઃఆᒾҰతڃ • # typed: ignore : શࠌུɼՄҎෆੋ༗Ꮘతఔࣜᛰ • # typed: false ɿ ᒾҰޠ๏ɼ༬ઃᆴɻ • # typed: trueɿᒾҰ༗ఆٛతܕผɼ • # typed: strict :ॴ༗తܕผधཁ༗ఆٛɻ • # typed: strongɿbug ଟɼෆཁ༻ɻ
Slide 22
Slide 22 text
Sorbet ܕผඪࣔ • ՄҎࡏఔࣜᛰத၏ܕผᩄ • ՄҎ༻ᘐཱత RBI ܕผఆٛ䈕 • ՄҎಉ࣌༻ɻୠੋෆೳॏෳඪࣔɻ
Slide 23
Slide 23 text
ܕผᩄ • ༻ T:Sig module ိ၏ܕผᩄɻ • ܕผᩄޙతఔࣜᛰґવੋ߹๏త Ruby ఔࣜᛰɻ • ՄҎሣᏓᏐ၏ܕผᩄɻ extend T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); n+1; end
Slide 24
Slide 24 text
RBI ܕผఆٛ䈕 • ܕผᩄաޙతఔࣜ፤ᎃመ࡞ɼबྃ RBI ܕผఆٛ 䈕ɻ • ೳሣৗᏐɼํ๏መᱪᏓᏐ၏ܕผඪࣔɻ extend T::Sig sig{params(n: Integer).returns(Integer)} def add1(n); end def add1(n) n+1 end
Slide 25
Slide 25 text
جຊܕผ • T.untyped • Ұൠܕผ • Boolean • Array & Hash • Nilable • Block & Proc & lambda
Slide 26
Slide 26 text
T.untyped • ᔒ༗څܕผ࣌ީత typeɻ • BasicObject ʢॴ༗݅తڞಉઌʣ ෆಉɼT.untyped ။શུաܕผᒾҰɻ • T.untyped => զෆࡏݷ • BasicObject => զෆಓɻ
Slide 27
Slide 27 text
Ұൠܕผ • 1 => Integer or Numeric • 3.14 => Float or Numeric • "hello" => String • :world => Symbol
Slide 28
Slide 28 text
Boolean • true => T::Boolean or TrueClass • false => T::Boolean or FalseClass • T::Boolean => Union(TrueClass ,FalseClass)
Slide 29
Slide 29 text
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]
Slide 30
Slide 30 text
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
Slide 31
Slide 31 text
Block & Proc & lambda • proc {|n| n * 2 } => T.proc.params(n: Integer).returns(Integer) • Proc.new{|n| n*2} => Proc
Slide 32
Slide 32 text
ಛघܕผ • ࿆ूܕผ T.any • ަूܕผ T.all
Slide 33
Slide 33 text
࿆ूܕผ 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")
Slide 34
Slide 34 text
ަूܕผ T.all • ಉ࣌༗ Module1 & Module2 ၷݸ Mixin • {params(x: T.all(Module1, Module2)).void} def requires_both(x) x.method1 # ok x.method2 # also ok end
Slide 35
Slide 35 text
ํ๏ܕผඪࣔ • ҰൠჩᏐ & ᮫伴ࣈჩᏐ • ՄᏓჩᏐ • block ჩᏐ • Void ճၚᆴ
Slide 36
Slide 36 text
ҰൠჩᏐ & ᮫伴ࣈჩᏐ extend T::Sig sig{params(n: Integer, s: String).returns(String)} def foo(n) "#{n} #{s}" end
Slide 37
Slide 37 text
ՄᏓჩᏐ • 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
Slide 38
Slide 38 text
block ჩᏐ • ཁՃ &blk ࠽ೳඪࣔჩᏐతܕผɻᔒՃత block ။ඃᙛ untyped sig {params(blk: T.proc.returns(Integer)).returns(Integer)} def foo(&blk) # <- yield end
Slide 39
Slide 39 text
Void ճၚᆴ • Ruby Ӭԕ။ճၚ࠷ޙҰߦɻୠ༗࣌ީੋ䭘䭓ᆴɻ • ඪ্ void తबՄҎආ໔ޡ༻ճၚᆴɻ sig {params(name: String).void} def greet(name) puts "Hello, #{name}!" end puts greet("Coscup") # ERROR !
Slide 40
Slide 40 text
ᏓᏐܕผඪࣔ • T.let • T.cast • T.bind
Slide 41
Slide 41 text
T.let • ઃఆᏓᏐత type • ෆ߹ཧత value ။༗ errorɻ x = T.let(10, Integer) y = T.let(10, String) # error
Slide 42
Slide 42 text
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
Slide 43
Slide 43 text
T.bind • self ڧ੍ܕ༻త • self ෆೳ༻ T.cast • ࡏ proc/block ཫ໘۰౸ instance_eval ࣌መ༻ T.bind(self, MyClass) self.method_on_my_class
Slide 44
Slide 44 text
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
Slide 45
Slide 45 text
আࡨޭೳ • ՄҎ༻ိᰖࣔҰݸᆴ༬ظతܕผɻ • Ұ։࢝ෆಓܕผత࣌ީ༻ɻ T.reveal_type(1) editor.rb:9: Revealed type: Integer(1) https://srb.help/7014
Slide 46
Slide 46 text
T.unsafe • զಓࣗݾࡏ၏ॄኄɻผզɻ class A def method_missing(method) puts "Called #{method}" end end T.unsafe(A.new).foo # => ok
Slide 47
Slide 47 text
ਐ֊ܕผఆٛ • Abstract class & interface • Sealed class • Final class
Slide 48
Slide 48 text
ҏἾ֥ূ • ࣥߦ༻త script ཁ༻ if __FILE__ == $PROGRAM_NAME แىိɻ • RSpec ။༗Ұେථ TypeErrorɻՄҎશ෦ ignoreɻ • ଟ Gem ؐᔒ༗ Type De fi nitionɻ၏ग़։ݯߩᘔతେ ࣌ػɻ
Slide 49
Slide 49 text
Steep • by Soutaro Matsumoto ɼ༻ Ruby ሜతɻ • ํతܕผᒾҰثɼʢҼҝ RBS ੋಉҰݸ࡞ऀʣ • ᯩଶᒾҰɻ • ༻ ᘐཱత RBS ܕผఆٛ䈕ɻ • gem install steep
Slide 50
Slide 50 text
Steep fi le target :app do check "lib" signature "sig" library "set", "pathname" end
Slide 51
Slide 51 text
Steep తਐࣜᒾҰ • ۰౸ᔒ༗ܕผᩄతఔࣜᛰɼ။ᙛ࡞ untyped ိ႔ཧɻ • untyped త݅။աॴ༗తᒾҰɻ • ༗ෆᒾҰత䈕ҊՄҎࡏ Steep fi le ཫ ignore ᎃɻ
Slide 52
Slide 52 text
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
Slide 53
Slide 53 text
RBI vs RBS • RBI: ෆՄҎఆٛ typeɼؐՄҎሣܕผ၏ਐ֊ఆٛɻ • RBS: ՄҎ၏ overloading • መࡍ্બ䬟ݸՄҎɼ༗۩(parlour) ՄҎ၏ɻ
Slide 54
Slide 54 text
֘༻䬟Ұݸʁ • Sorbet • ൺֱख़ɼࣕ Stripe ࣗݾ༗ࡏ༻ɻ
Slide 55
Slide 55 text
݁ • Ruby ܕผᒾҰثਖ਼ࡏᚙలதɻ • Sorbet ੋલൺֱख़తᒾҰثɻ • ݱࡏੋሣ Ruby ܕผᒾҰ࡞ग़ߩᘔతେ࣌ػɻ
Slide 56
Slide 56 text
Q&A • Өยࡏ https://johnlin.vc/ coscup-2022/ • ՄҎࡏ twitter ্ፙ౸զ @johnlinvc • ༗ڵझՄҎగ㕕զత blog https://johnlin.vc
Slide 57
Slide 57 text
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