Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ruby 
型別檢查工具簡介

Ruby 
型別檢查工具簡介

於 Coscup 2022 發表。
https://johnlin.vc/coscup-2022/

Johnlin

July 31, 2022
Tweet

More Decks by Johnlin

Other Decks in Programming

Transcript

  1. Ruby

    ܕผᒾҰ޻۩؆հ
    John Lin (@johnlinvc)

    View full-size slide

  2. ᮫ԙզ
    • John Lin

    • تᓣ Ruby & Swiftɻओ㭎Swift Taipei Meetupɻ

    • Twitter: @johnlinvc

    • Blog: https://johnlin.vc/

    • Principle Solution Architect @ West Pharmaceutical
    Service (੢ࣜဌऱ)

    View full-size slide

  3. ڧྗ㐸࠽த
    • ୆๺ओཁੋ၏ᬭྍᢛ޻ۀ IoT ɻूᅶᚙలॏ৺೭Ұɻ

    • google "cake resume west"ɼ༗ෟ਋ࢿൣᅴɻ

    • ౤ཤ㑖త࣌㘸ੋ John Lin հ঺తɻိత࿩ referral bonus
    ෼㟬Ұ൒ɻ

    • Coscup ᩶ॿ঎

    View full-size slide

  4. Agenda
    • Ruby తܕผܥ౷

    • ܕผᒾҰత޷႔

    • Ruby ܕผᒾҰ޻۩తಛ৭

    • Sorbet

    • Steep

    • ൺֱ Ruby తܕผᒾҰ޻۩

    • Q&A

    View full-size slide

  5. Ruby తܕผܥ౷
    • ڧܕผ Strong Type

    • ಈଶܕผ Dynamic Type

    • יࢠܕผ Duck typing

    • ॴ༗౦੢౎ੋ෺݅ Everything is object

    • ᄸҰ៺ঝ Single Inheritance

    • Mixin

    • nil

    View full-size slide

  6. ܕผᒾҰత޷႔
    • ᒾҰଧࣈࡨޡ

    • ᒾҰჩᏐၚᬇࡨޡ

    • ఏߴఔࣜᛰతՄᯪੑ

    • ՄҎॱศఏڙఔࣜᛰతࢿ㘤څ IDEɻ

    View full-size slide

  7. Ruby ܕผᒾҰ޻۩తڞಉಛ৭
    • ᔒ༗׭ํతܕผᒾҰ޻۩

    • ઴ਐࣜܕผᒾҰ Gradual type checker.

    • ܕผఆٛ䈕 Type def
    fi
    les

    View full-size slide

  8. ᔒ༗׭ํతܕผᒾҰ޻۩
    • ᔒ༗׭ํతܕผᒾҰ޻۩ɻ

    • ୠੋ༗׭ํతܕผඪ஫ɼRuby Signature (RBS) ɻ

    • Python & javascript ໵ੋҰᒬɻ

    View full-size slide

  9. RBS ܕผఆٛ䈕
    • Ruby ׭ํతܕผఆٛ֨ࣜɻ

    • ᘐཱ䈕Ҋɻ

    • ՄҎኺݪ࢝ᛰࣗಈ㗞ੜൣຊɻ

    View full-size slide

  10. ઴ਐࣜܕผᒾҰ


    Gradual Type Check
    • ՄҎ୞ᒾҰ෦෼తఔࣜᛰɻ

    • ߱௿ಋೖ೉౓ɻ

    • Python(mypy) & TypeScript ౎ੋɻ

    View full-size slide

  11. ܕผఆٛ䈕
    • ᘐཱత䈕Ҋɻ

    • ఆٛྃܕผɼৗᏐɼํ๏ɼݸᱪᏓᏐతܕผɻ


    class Foo


    def bar(s); end


    end
    class Foo


    def bar: (s: String) -> String


    end

    View full-size slide

  12. ܕผ஫ᩄ (type annotation)
    • ࡏఔࣜᛰதՃ্Ḽղ҃ੋֹ֎తඪࣔɻ

    • ૾ੋ C++, Python ҃ Typescript ౎ੋɻ
    class Foo


    sig{params(s: String).returns(String)}


    def bar(s)


    end


    end

    View full-size slide

  13. ܕผఆٛ䈕త༏᠍ᴍ
    • ᠍ᴍɿఔࣜ࿨ܕผఆٛࡏෆಉ䈕ҊɼՄೳ။๨هվɻ

    • ༏ᴍɿఔࣜޠ๏ൺֱᄸ७ɻ

    View full-size slide

  14. ܕผఆٛ䈕


    V.S. ܕผ஫ᩄ (type annotation)
    • Matz:

    • ఔࣜෆधཁܕผඪࣔब။ಈɻtype annotation ҧ൓ྃ
    DRY(Don't Repeat Yourself) ݪଇɻ

    • ະိՊٕ଍ⴺਐ㑊ޙɼ༗Մೳ׬શෆधཁܕผఆٛ䈕ɻ

    View full-size slide

  15. Ruby ܕผ෼ੳ޻۩
    • Sorbet

    • Steep

    View full-size slide

  16. Sorbet


    • ༝ Stripe ։ᚙɼ༻ C++ & Rubyሜతɻ

    • ᯩଶᒾҰ ˍ ಈଶᒾҰ

    • 㚎ݐޠݴ࢕෰ثڠఆ(Language Server Protocol, LSP)

    • ෆಉ౳ڃత઴ਐࣜᒾҰ

    • ಉ࣌ࢧԉ ܕผ஫ᩄ(Type Annotation) ᢛ RBI ܕผఆٛ䈕ɻ

    View full-size slide

  17. ᯩଶᒾҰ
    • ࣥߦsorbet ိᒾҰܕผɼෆधཁਅతࣥߦఔࣜɻ

    • ࢖༻৘ڥɿሜఔࣜதɼ౥഑ lsp serverɻ࿈᠃੔߹(CI)ɻ

    View full-size slide

  18. ಈଶᒾҰ
    • ࣥߦఔࣜత࣌ީɼSorbet ။ᒾҰܕผฒ׌㗞ੜࡨޡ҃Log

    • ࢖༻৘ڥɿ࿈᠃੔߹(CI)தతᄸݩଌࢼ҃੔߹ଌࢼɻ༬උ؀
    ڥ(Staging)ɻਖ਼ࣜ؀ڥɻ

    View full-size slide

  19. 㚎ݐޠݴ࢕෰ثڠఆ
    • ౥഑ VSCode ҃ Emacs ౳ࢧԉ ޠݴ࢕෰ثڠఆ తฤाث
    ࣌ɼՄҎଈ࣌ᰖࣔࡨޡɻෆधཁ㠥֎ࣥߦࢦྩɻ

    • ໵ఏڙྃ௓౸ఆٛɼᰖࣔ࢖༻஍ᴍɼᏓᏐվ໊౳ޭೳɻ

    View full-size slide

  20. ෆಉ౳ڃత઴ਐࣜᒾҰ
    • ࡏ䈕Ҋ։಄Ճ্ਆحḼղ # typed: LEVEL बՄҎઃఆᒾҰత౳ڃ


    • # typed: ignore : ׬શࠌུɼՄҎෆੋ༗Ꮘతఔࣜᛰ


    • # typed: false ɿ ୞ᒾҰޠ๏ɼ༬ઃᆴɻ


    • # typed: trueɿᒾҰ༗ఆٛతܕผɼ


    • # typed: strict :ॴ༗తܕผ౎धཁ༗ఆٛɻ


    • # typed: strongɿbug ኷ଟɼෆཁ༻ɻ

    View full-size slide

  21. Sorbet ܕผඪࣔ
    • ՄҎࡏఔࣜᛰத၏ܕผ஫ᩄ

    • ໵ՄҎ༻ᘐཱత RBI ܕผఆٛ䈕

    • ՄҎಉ࣌࢖༻ɻୠੋෆೳॏෳඪࣔɻ

    View full-size slide

  22. ܕผ஫ᩄ
    • ࢖༻ T:Sig module ိ၏ܕผ஫ᩄɻ

    • ܕผ஫ᩄޙతఔࣜᛰґવੋ߹๏త Ruby ఔࣜᛰɻ

    • ՄҎሣᏓᏐ၏ܕผ஫ᩄɻ
    extend T::Sig


    sig{params(n: Integer).returns(Integer)}


    def add1(n); n+1; end

    View full-size slide

  23. RBI ܕผఆٛ䈕
    • ೺ܕผ஫ᩄաޙతఔࣜ፤ᎃመ࡞ɼब੒ྃ RBI ܕผఆٛ
    䈕ɻ

    • ୞ೳሣৗᏐɼํ๏࿨መᱪᏓᏐ၏ܕผඪࣔɻ
    extend T::Sig


    sig{params(n: Integer).returns(Integer)}


    def add1(n); end
    def add1(n)


    n+1


    end

    View full-size slide

  24. جຊܕผ
    • T.untyped

    • Ұൠܕผ

    • Boolean

    • Array & Hash

    • Nilable

    • Block & Proc & lambda

    View full-size slide

  25. T.untyped
    • ᔒ༗څܕผ࣌ީత typeɻ

    • ࿨ BasicObject ʢॴ༗෺݅తڞಉ૆ઌʣ ෆಉɼT.untyped
    ။׬શུաܕผᒾҰɻ

    • T.untyped => զෆࡏݷ

    • BasicObject => զෆ஌ಓɻ

    View full-size slide

  26. Ұൠܕผ
    • 1 => Integer or Numeric

    • 3.14 => Float or Numeric

    • "hello" => String

    • :world => Symbol

    View full-size slide

  27. Boolean
    • true => T::Boolean or TrueClass

    • false => T::Boolean or FalseClass

    • T::Boolean => Union(TrueClass ,FalseClass)

    View full-size slide

  28. 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]

    View full-size slide

  29. 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

    View full-size slide

  30. Block & Proc & lambda
    • proc {|n| n * 2 } => T.proc.params(n:
    Integer).returns(Integer)

    • Proc.new{|n| n*2} => Proc

    View full-size slide

  31. ಛघܕผ
    • ࿆ूܕผ T.any

    • ަूܕผ T.all

    View full-size slide

  32. ࿆ूܕผ 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")

    View full-size slide

  33. ަूܕผ T.all
    • ಉ࣌༗ Module1 & Module2 ၷݸ Mixin


    {params(x: T.all(Module1, Module2)).void}


    def requires_both(x)


    x.method1 # ok


    x.method2 # also ok


    end

    View full-size slide

  34. ํ๏ܕผඪࣔ
    • ҰൠჩᏐ & ᮫伴ࣈჩᏐ

    • ՄᏓ௕౓ჩᏐ

    • block ჩᏐ

    • Void ճၚᆴ

    View full-size slide

  35. ҰൠჩᏐ & ᮫伴ࣈჩᏐ
    extend T::Sig


    sig{params(n: Integer, s: String).returns(String)}


    def foo(n)


    "#{n} #{s}"


    end

    View full-size slide

  36. ՄᏓ௕౓ჩᏐ
    • 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

    View full-size slide

  37. block ჩᏐ
    • ཁՃ &blk ࠽ೳඪࣔჩᏐతܕผɻᔒՃత࿩ block ။ඃᙛ੒
    untyped
    sig {params(blk: T.proc.returns(Integer)).returns(Integer)}


    def foo(&blk) # <-


    yield


    end

    View full-size slide

  38. Void ճၚᆴ
    • Ruby Ӭԕ။ճၚ࠷ޙҰߦɻୠ༗࣌ީੋ䭘䭓ᆴɻ

    • ඪ্ void త࿩बՄҎආ໔ޡ༻ճၚᆴɻ
    sig {params(name: String).void}


    def greet(name)


    puts "Hello, #{name}!"


    end


    puts greet("Coscup") # ERROR !

    View full-size slide

  39. ᏓᏐܕผඪࣔ
    • T.let

    • T.cast

    • T.bind

    View full-size slide

  40. T.let
    • ઃఆᏓᏐత type

    • ෆ߹ཧత value ။༗ errorɻ
    x = T.let(10, Integer)


    y = T.let(10, String) # error

    View full-size slide

  41. 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

    View full-size slide

  42. T.bind
    • ೺ self ڧ੍᫚ܕ༻త

    • self ෆೳ༻ T.cast

    • ࡏ proc/block ཫ໘۰౸ instance_eval ࣌኷መ༻
    T.bind(self, MyClass)


    self.method_on_my_class

    View full-size slide

  43. 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

    View full-size slide

  44. আࡨޭೳ
    • ՄҎ༻ိᰖࣔ๭Ұݸᆴ༬ظతܕผɻ

    • Ұ։࢝ෆ஌ಓܕผత࣌ީ኷޷༻ɻ
    T.reveal_type(1)
    editor.rb:9: Revealed type: Integer(1) https://srb.help/7014

    View full-size slide

  45. T.unsafe
    • զ஌ಓࣗݾࡏ၏ॄኄɻผ؅զɻ
    class A


    def method_missing(method)


    puts "Called #{method}"


    end


    end


    T.unsafe(A.new).foo # => ok

    View full-size slide

  46. ਐ֊ܕผఆٛ
    • Abstract class & interface

    • Sealed class

    • Final class

    View full-size slide

  47. ҏἾ֥ূ
    • ௚઀ࣥߦ༻త script ཁ༻ if __FILE__ ==
    $PROGRAM_NAME แىိɻ

    • RSpec ။༗Ұେථ TypeErrorɻՄҎશ෦ ignoreɻ

    • ኷ଟ Gem ౎ؐᔒ༗ Type De
    fi
    nitionɻ၏ग़։ݯߩᘔతେ޷
    ࣌ػɻ

    View full-size slide

  48. Steep
    • by Soutaro Matsumoto ɼ༻ Ruby ሜతɻ

    • ൒׭ํతܕผᒾҰثɼʢҼҝ࿨ RBS ੋಉҰݸ࡞ऀʣ

    • ᯩଶᒾҰɻ

    • ࢖༻ ᘐཱత RBS ܕผఆٛ䈕ɻ

    • gem install steep

    View full-size slide

  49. Steep
    fi
    le
    target :app do


    check "lib"


    signature "sig"


    library "set", "pathname"


    end

    View full-size slide

  50. Steep త઴ਐࣜᒾҰ
    • ۰౸ᔒ༗ܕผ஫ᩄతఔࣜᛰɼ။ᙛ࡞ untyped ိ႔ཧɻ

    • untyped త෺݅။௓աॴ༗తᒾҰɻ

    • ༗ෆ૝ᒾҰత䈕ҊՄҎࡏ Steep
    fi
    le ཫ ignore ᎃɻ

    View full-size slide

  51. 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


    View full-size slide

  52. RBI vs RBS
    • RBI: ෆ୞ՄҎఆٛ typeɼؐՄҎሣܕผ၏ਐ֊ఆٛɻ

    • RBS: ՄҎ၏ overloading

    • መࡍ্બ䬟ݸ౎ՄҎɼ༗޻۩(parlour) ՄҎ၏᫚׵ɻ

    View full-size slide

  53. ֘༻䬟Ұݸʁ
    • Sorbet

    • ൺֱ੒ख़ɼࣕ׌ Stripe ࣗݾ༗ࡏ༻ɻ

    View full-size slide

  54. ݁࿦
    • Ruby ܕผᒾҰثਖ਼ࡏ೤྽ᚙలதɻ

    • Sorbet ੋ໨લൺֱ੒ख़తᒾҰثɻ

    • ݱࡏੋሣ Ruby ܕผᒾҰ࡞ग़ߩᘔతେ޷࣌ػɻ

    View full-size slide

  55. Q&A
    • ౤Өยࡏ https://johnlin.vc/
    coscup-2022/

    • ՄҎࡏ twitter ্ፙ౸զ
    @johnlinvc

    • ༗ڵझՄҎగ㕕զత blog 

    https://johnlin.vc

    View full-size slide

  56. 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

    View full-size slide