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

Ruby 3の新機能としての静的型検査の開発

Ruby 3の新機能としての静的型検査の開発

Soutaro Matsumoto

March 10, 2021
Tweet

More Decks by Soutaro Matsumoto

Other Decks in Programming

Transcript

  1. 3VCZͷ৽ػೳͱͯ͠ͷ

    ੩తܕݕࠪͷ։ൃ
    দຊफଠ࿠

    View Slide

  2. দຊफଠ࿠
    w !TPVUBSP
    w 3VCZίϛολ ʙ


    3VCZͷܕͷ࢓ࣄ
    w 4RVBSFגࣜձࣾ ʙ


    ࣾ಺ͷ3VCZϓϩάϥϜʹܕΛ෇͚Δ࢓ࣄ
    w ത࢜ʢ޻ֶʣ೥ஜ೾େֶ

    3VCZϓϩάϥϜͷܕΛਪ࿦

    View Slide

  3. ֓ཁ
    w 3VCZͷܕղੳػೳ
    w 3VCZͱܕͷྺ࢙
    w ܕݕࠪπʔϧͷ։ൃͷ༷ʑͳଆ໘

    View Slide

  4. 3VCZͷܕղੳػೳ
    w ܕΛॻͨ͘Ίͷݴޠ3#4Λఆٛ
    w ܕఆٛΛॲཧ͢ΔͨΊͷϥΠϒϥϦͱඪ४ϥΠϒϥϦͷܕఆٛΛಉࠝ
    w ίϛϡχςΟͰϥΠϒϥϦͷܕఆٛΛهड़ͯ͠഑෇͢Δํ๏Λఏڙ
    w 3#4ؔ࿈ͷπʔϧ͸5ZQF1SPGΛಉࠝ
    w ܕݕࠪث͸ಉࠝͳ͠

    View Slide

  5. # The conference object represents a conference.


    #


    # conf = Conference.new("RubyConf 2020")


    # conf.talks << talk1


    # conf.talks << talk2


    #


    class Conference


    # The name of the conference.


    attr_reader name: String


    # Talks of the conference.


    attr_reader talks: Array[Talk]


    def initialize: (String name) -> void


    # Yields all speakers of the conference.


    # Deduped, and no order guaranteed.


    def each_speaker: { (Speaker) -> void } -> void


    | () -> Enumerator[Speaker, void]


    end

    View Slide

  6. Union types
    Generics
    untyped type
    String | Symbol


    Integer? #== Integer | nil
    Hash[String, Array[Integer]]


    Array[String | Integer]
    def eval: (String) -> untyped
    Tuple & record
    [Integer, String] # ݻఆ௕ͷ഑ྻ


    { id: Integer, name: String } # Ωʔݻఆͷϋογϡ
    Class/module types
    Object, Kernel


    singleton(String), singleton(Array)

    View Slide

  7. 3#4
    w 3VCZίʔυͱ͸ผͷϑΝΠϧʹهड़
    w 3VCZͱͷ׬ᘳͳޓ׵ੑ
    w 3VCZίʔυʹܕ஫ऍΛೖΕͳ͍ͱ͍͏ͩ͜ΘΓ
    w ͲΜͳ3VCZϓϩάϥϜͰ΋ɺ3#4͕ॻ͚Ε͹ܕ͕ॻ͚Δ

    View Slide

  8. class Server < ApplicationRecord


    validates :name, :length => { :in => 3..30 }


    validates :uri, :length => { :in => 20..200 }


    validates :ordinal, :numericality => true, :uniqueness => true


    end
    class Server < ApplicationRecord


    attr_accessor name (): String


    attr_accessor uri (): String


    def name_changed: () -> bool


    def name_change: () -> [String?, String?]


    def name_will_change: () -> void


    def name_was: () -> String?


    def name_previously_changed?: () -> bool


    def name_previously_was: () -> String?


    def name_before_last_save: () -> String?


    def uri_changed: () -> bool


    def uri_change: () -> [String?, String?]




    View Slide

  9. 5ZQF1SPG
    w ૉͷ3VCZϓϩάϥϜΛೖྗͱͯ͠3#4Λੜ੒
    w ந৅ղऍʹجͮ͘ΞϧΰϦζϜ
    w 11-Ͱ঺հ
    $ typeprof exe/entrypoint

    View Slide

  10. [email protected]@DPMMFDUJPO
    w ίϛϡχςΟͰϥΠϒϥϦͷܕΛॻ͍ͯ഑෇ͯ͠΋Β͏৔ॴ
    w 5ZQF4DSJQUͷ%F
    fi
    OJUFMZ5ZQFEɺ1ZUIPOͷ5ZQF4IFE
    w ແݶʹ͋Δ3VCZϥΠϒϥϦͷܕ৘ใΛॻ͍ͯ΋ΒΘͳ͍ͱ͍͚ͳ͍
    [email protected]@DPMMFDUJPO

    View Slide

  11. 3VCZͷܕαϙʔτ
    w 3#4ͰϥΠϒϥϦͷܕΛॻ͚Δ
    w [email protected]@DPMMFDUJPOͰϥΠϒϥϦͷܕΛ഑෇͢Δ
    w 5ZQF1SPGͰ3#4Λੜ੒͢Δ
    w ͳʹ͔ͷπʔϧͰ3VCZϓϩάϥϜͷܕݕࠪΛ͢Δ

    View Slide

  12. 3VCZͷܕαϙʔτ
    w 3#4ͰϥΠϒϥϦͷܕΛॻ͚Δ
    w [email protected]@DPMMFDUJPOͰϥΠϒϥϦͷܕΛ഑෇͢Δ
    w 5ZQF1SPGͰ3#4Λੜ੒͢Δ
    w ͳʹ͔ͷπʔϧͰ3VCZϓϩάϥϜͷܕݕࠪΛ͢Δ
    ˡ3VCZ

    View Slide

  13. 4UFFQ
    w 3#4ͱ3VCZϓϩάϥϜͱͷ੔߹ੑΛݕࠪ
    w 3VCZϓϩάϥϜ಺ʹܕ஫ऍΛهࡌ͢Δඞཁ͕͋Δ
    w 3#4ͰܕΛॻ͘ඞཁ͕͋Δ
    w 11-Ͱ঺հ

    View Slide

  14. ࠓ೔ͷ࿩୊
    w 3#4
    w [email protected]@DPMMFDUJPO
    w 4UFFQʢ3VCZͰ͸ͳ͍͕ɺ࿩͕ਐ·ͳ͍ͷͰʣ

    View Slide

  15. ֓ཁ
    w 3VCZͷܕղੳػೳ
    w 3VCZͱܕͷྺ࢙
    w ܕݕࠪπʔϧͷ։ൃͷ༷ʑͳଆ໘

    View Slide

  16. ྺ࢙
    w શ෦ܕΛਪ࿦͠Α͏ͱ͢Δάϧʔϓ
    w ར༻ऀ͕ॻ͍ͨϓϩάϥϜʹܕ஫ऍ͕͋Δ͜ͱΛԾఆ͢Δάϧʔϓ

    .-ͷܕਪ࿦ʹجͮ͘΋ͷʢদຊ ೆग़ʣ
    ϑϩʔղੳʹجͮ͘΋ͷʢদຊ ೆग़ʣ
    %JBNPOECBDL3VCZʢ'VSS 'PTUFSʣ
    4UFFQʢদຊʣ
    4PSCFU 4USJQF

    5ZQF1SPGʢԕ౻ʣ
    NNDʢࡾӜʣ
    +VTUJO5JNF4UBUJD5ZQF$IFDLJOHGPS

    %ZOBNJD-BOHVBHFTʢ3FO 'PTUFSʣ

    View Slide

  17. 3VCZʹ޲͚ͯ

    4UFFQʢদຊʣ
    4PSCFU 4USJQF

    5ZQF1SPGʢԕ౻ʣ
    NNDʢࡾӜʣ
    3VCZʹܕΛೖΕΔ͜ͱΛએݴ .BU[


    3VCZʹܕݕࠪثΛೖΕͳ͍͜ͱΛܾఆ .BU[

    3#4ͷಋೖΛܾఆ .BU[

    5ZQF1SPGͷಋೖΛܾఆ .BU[

    ౦๺େֶిؾ௨৴ݚڀॴڞಉϓϩδΣΫτ
    SVCZUZQFTNFFUJOH

    View Slide

  18. 4PSCFU
    w IUUQTTPSCFUPSH
    w 3VCZ%4-ͰܕΛॻ͘
    class Conference


    extend T::Sig


    sig do


    params(name: String).void


    end


    def initialize(name:)


    @name = name


    @speakers = T.let([], T::Array[Speaker])


    end


    end

    View Slide

  19. 4UFFQ
    w ϓϩάϥϜͷܕ͸ผͷఆٛϑΝΠϧʹॻ͘
    w ίϝϯτͰΠϯϥΠϯܕ஫ऍ
    w ࣮ߦ࣌ͷґଘϥΠϒϥϦͳ͠
    class Conference


    def each_speaker(&block)


    # @type var speakers: Array[Speak


    speakers = []


    talks.each do |talk|


    speakers << talk.speaker


    end


    speakers.each(&block)


    end


    end
    class Conference


    def each_speaker: { (Speaker) -> void } -> void


    end

    View Slide

  20. ֓ཁ
    w 3VCZͷܕղੳػೳ
    w 3VCZͱܕͷྺ࢙
    w ܕݕࠪπʔϧͷ։ൃͷ༷ʑͳଆ໘

    View Slide

  21. ͍Ζ͍Ζͳཁૉ
    w ܕγεςϜͷઃܭ
    w αϒλΠϐϯά
    w ༷ʑͳࠔ೉
    w ܕఆٛͷςετ
    w *%&࿈ܞͷ։ൃ

    View Slide

  22. αϒλΠϐϯά
    w %VDLUZQJOHͱ͍͏֓೦
    w ΦϒδΣΫτ͕ಛఆͷΫϥεͰ͋Δ͜ͱΛԾఆ͠ͳ͍
    w ϝιου͕͋Ε͹ྑ͍
    w ߏ଄త෦෼ܕͷ֓೦ͱ͍ۙ

    View Slide

  23. ͥΜͿߏ଄త෦෼ܕͰߦͧ͘💪
    w 4USJOHͷdϝιουΛશ෦࠶࣮૷ͨ͠ΫϥεΛ࡞Δ͜ͱ͸ඇݱ࣮త
    w 3VCZͷ࣮ߦ࣌ͷҙຯͱҰக͠ͳ͍
    object.is_a?(String)
    case json


    when String


    ...


    when Numeric


    ...


    when Array


    ...


    end

    View Slide

  24. ΍Ίͨ
    w ΠϯλϑΣʔεͷΈߏ଄తʹ෦෼ܕΛ൑ఆ
    w ଞ͸Ϋϥεͷܧঝؔ܎ʹΑͬͯ൑ఆ
    interface _Appendable


    def <<: (String) -> void


    end
    class String


    def <<: (String) -> String


    end
    class Array[Elem]


    def <<: (Elem) -> Array[Elem]


    end
    class Integer


    def <<: (Integer) -> Integer


    end
    String <: _Appendable # => ✅


    Array[String] <: _Appendable # => ✅


    Integer <: _Appendable # => 💣

    View Slide

  25. ༷ʑͳࠔ೉
    w ੍໿ɿطଘͷ3VCZίʔυ͕Ͱ͖Δ͚ͩܕݕࠪͰ͖ͯཉ͍͠
    w 3VCZʹܕ஫ऍΛೖΕΔ͜ͱ͸Ͱ͖ͳ͍ʢ.BU[ܾఆʣ
    w ͍Ζ͍ΖͱఘΊΔ͔͠ͳ͔ͬͨ
    ࣗ༝ͳΦʔόʔϥΠυ
    $PWBSJBOUͳίϨΫγϣϯ
    'MPXTFOTJUJWFͳղੳ
    ഑ྻͷΞΫηε
    ϝλϓϩάϥϛϯάʹΑΔఆٛ

    View Slide

  26. ࣗ༝ͳΦʔόʔϥΠυ
    w αϒΫϥε͕উखʹ޷͖ͳҙຯɾܕͰಉ໊ͷϝιουΛఆ͍ٛͯ͠Δ
    w 0CKFDUTFMFDUͱ"SSBZTFMFDU
    w 0CKFDUNFUIPEͱ)5513FRVFTUNFUIPE
    w .PEVMFDMBTT
    def select: (Array[IO], Array[IO], Array[IO]) -> Array[Array[IO]]
    def select: () { (Elem) -> top } -> Array[Elem]


    | () -> Enumerator[Elem, Array[Elem]]
    0CKFDUTFMFDU
    "SSBZTFMFDU

    View Slide

  27. ఘΊͨ
    w ΦʔόʔϥΠυͰϝιουͷܕ͕มΘΔ΋ͷ͸ɺϓϩάϥϚͷ੹೚
    w ϝιουͷܕʹΞϊςʔγϣϯΛ෇͚Δ㱺਺͕ଟ͗͢Δ
    w ࣮ࡍʹ͸໰୊ʹͳΒͳͦ͞͏ʢͲ͏ͤ3VCZͰ࣮ߦͰ͖ͳ͍͔Βʣ
    def get_method(object)


    # Object#methodͩͱࢥͬͯݺͼग़͢


    object.method(:to_s)


    end


    get_method("string")


    get_method(request)
    def get_method: (Object) -> void

    View Slide

  28. $PWBSJBOUͳίϨΫγϣϯ
    w "SSBZ<4USJOH>ͱ"SSBZ<0CKFDU>ͷؔ܎
    # @type var strings: Array[String]


    strings = ["foo", "bar"]


    # @type var objects: Array[Object]


    objects = strings # ͜ͷ୅ೖΛڐ͔͢ʁ


    objects.push(3)


    strings[2] # StringʁIntegerʁ

    View Slide

  29. ྑ͍ํ๏͸ͳ͍͔ʁ
    w +BWBͷΑ͏ʹ΍Δͷ͸Ͳ͏͔ʁ
    w ಛผͳ(FOFSJDTͷߏจͰɺҾ਺ʹܕม਺͕ग़ͯ͘ΔϝιουΛফ͢
    def read_array: (Array[? extends Object]) -> void
    class Array[Elem]


    def []: (Integer) -> Elem # ࢒͢


    def <<: (Elem) -> Array[Elem] # ফ͢


    end

    View Slide

  30. class Array[Elem]


    def find: (Elem) -> Elem?


    end

    View Slide

  31. class Array[Elem]


    def find: (Elem) -> Elem?


    end
    class Array[Elem]


    def find: (top) -> Elem?


    end

    View Slide

  32. class Array[Elem]


    def find: (Elem) -> Elem?


    end
    class Array[Elem]


    def find: (top) -> Elem?


    end
    # ൺֱؔ਺Λ֎͔Β౉͢ίϨΫγϣϯͩͱμϝͳͷͰ͋Μ·Γ࢖͍ಓ͕ͳͦ͞͏


    class Set[Elem]


    def initialize: { (Elem, Elem) -> Integer } -> void


    def find: (Elem) -> Elem?


    end

    View Slide

  33. ఘΊͨ
    w ഑ྻͷཁૉ͸$PWBSJBOUͩͱܾΊͨ
    w ੈͷதͦ͏͍͏͜ͱʹͳ͍ͬͯΔʢ+BWB΋5ZQF4DSJQU΋ͦ͏ʣ
    class Array[unchecked out Elem]


    def <<: (Elem) -> Array[Elem]


    def pop: () -> Elem? # ͦ΋ͦ΋pop͕μϝ


    end

    View Slide

  34. ܕఆٛͷςετ
    w ϥΠϒϥϦͷܕΛॻ͍ͯཉ͍͠
    w ܕݕࠪثͳ͠ͰܕΛॻ͘ͷ͸ແཧ
    w 4UFFQΛ࢖͏ͷ͸ͦΕͳΓʹେม
    w ૊ΈࠐΈϥΠϒϥϦͷιʔείʔυ͸$
    w ॻ͍ͨܕͷਖ਼͠͞ΛͳΜͱͳ֬͘ೝ͢Δํ๏͕ඞཁ

    View Slide

  35. ܕఆٛͷςετ
    w ࣮ߦ࣌ݕࠪͱ૊Έ߹ΘͤΔํ๏ʢ૊ΈࠐΈϥΠϒϥϦͰ࢖༻ʣ
    w 4UFFQΛ࢖͏ํ๏ʢ[email protected]@DPMMFDUJPOͰ࢖༻ʣ
    w ґଘ͕͋ΔͷͰɺςετ࣮ߦ͕ࠔ೉
    w ظ଴͞ΕΔܕΤϥʔΛอଘ͓͍ͯͯ͠ൺֱ
    # io.read(0)


    assert_send_type "(Integer) -> String", io, :read, 0
    $ steep check --with-expectations=test.yml

    View Slide

  36. *%&࿈ܞͷ։ൃ
    w 4UFFQͷ*%&࿈ܞػೳ
    w -BOHVBHF4FSWFS1SPUPDPMΛར༻
    w Τϥʔใࠂɺิ׬ɺυΩϡϝϯτද
    ࣔɺఆٛʹδϟϯϓ
    w ࣮૷ɾௐ੔ʹແݶʹ͕͔͔࣌ؒΔ

    View Slide

  37. ิ׬ͷ࣮૷
    w 4UFFQͰ͸3VCZίʔυதͷϝιουݺͼग़͠ɺม਺໊ͳͲͷҰ෦ͷཁૉ
    ʹ͍ͭͯิ׬Λఏڙ

    View Slide

  38. ิ׬ީิͷੜ੒
    foo.ba← ͜͜ʂ foo.← ͜͜ʂ
    w ͜Ε͸ਖ਼͍͠3VCZίʔυ
    w ܕݕࠪͯ͠ɺΧʔιϧҐஔͷࣜͷܕ
    ͔Βิ׬ީิΛੜ੒
    w ͜Ε͸ߏจΤϥʔ
    w Χʔιϧͷલ͕ͩͬͨΒɺҰจࣈ
    ফͯ͠Έͯɺߏจղੳ
    w ղੳͰ͖ͨΒͦͷܕ৘ใ͔Βิ׬
    w ҙ֎ͱྑ͍ײ͡Ͱಈ͘

    View Slide

  39. ީิੜ੒଎౓ͷ޲্
    w ίʔυ͕௕͍ʢߦͱ͔ʣͱܕݕ͕ࠪ஗͍ʢ໨ඪ͸ඵʣ

    㱺ؔ܎ͳ͍෦෼Λফ͔ͯ͠Βܕݕࠪ͢Δ
    class Foo


    include Bar


    def foo


    f # ͜͜Ͱิ׬


    end


    def bar


    ...


    end


    w 4UFFQͷܕݕࠪʹ͸࠷΋಺ଆͷEFG
    Ҏ֎͸ؔ܎ͳ͍
    w ϝιουͷܕ͸3#4͔ΒಡΉ
    w Ωϟογϡͷঢ়گʹ΋ΑΔ͕ɺ࠷
    ѱͰඵ͘Β͍

    View Slide

  40. ·ͱΊ
    w 3VCZͷܕղੳػೳͷ঺հ
    w 3VCZ޲͚ͷܕݕࠪπʔϧ͸࣮༻తͳ΋ͷ͕ग़͖͍ͯͯΔ
    w ༷ʑͳϓϩάϥϛϯάݴޠͰͷ੍ݶɾଥڠΛͦͷ··Ҿ͖ܧ͍Ͱ͍Δ
    w ϓϩάϥϚͷೲಘײ͕ࢦ਑
    w ܕݕࠪثͷ࣮૷Ҏ֎ʹ΍Δ͜ͱ͕๲େʹ͋Δ

    View Slide

  41. w ଟ૬Ϩίʔυܕʹجͮ͘3VCZϓϩάϥϜͷܕਪ࿦ দຊೆग़
    w 3VCZϓϩάϥϜͷ੍ޚϑϩʔղੳͱͦͷ݈શੑͷূ໌ দຊೆग़
    w 4UBUJD5ZQF*OGFSFODFGPS3VCZ 'VSS"O'PTUFS)JDLT
    w +VTUJO5JNF4UBUJD5ZQF$IFDLJOHGPS%ZOBNJD-BOHVBHFT 3FO'PTUFS
    w 1SPHSFTTSFQPSU3VCZʹ͓͚Δ੩తܕղੳͷ࣮ݱʹ޲͚ͯ ԕ౻দຊ্໺ॅҪদຊ
    w 4PSCFUIUUQTTPSCFUPSH
    w 4UFFQIUUQTHJUIVCDPNTPVUBSPTUFFQ
    w 3#4IUUQTHJUIVCDPNSVCZSCT
    w 5ZQF1SPGIUUQTHJUIVCDPNNBNFUZQFQSPG
    w [email protected]@[email protected]@DPMMFDUJPO

    View Slide