Ruby 型別檢查工具簡介
by
Johnlin
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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