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

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

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

1fab9d01b25e99522f3dfd01e3d4cb51?s=128

Soutaro Matsumoto

March 10, 2021
Tweet

Transcript

  1. 3VCZͷ৽ػೳͱͯ͠ͷ 
 ੩తܕݕࠪͷ։ൃ দຊफଠ࿠

  2. দຊफଠ࿠ w !TPVUBSP w 3VCZίϛολ ʙ 
 3VCZͷܕͷ࢓ࣄ w 4RVBSFגࣜձࣾ

    ʙ 
 ࣾ಺ͷ3VCZϓϩάϥϜʹܕΛ෇͚Δ࢓ࣄ w ത࢜ʢ޻ֶʣ೥ஜ೾େֶ 
 3VCZϓϩάϥϜͷܕΛਪ࿦
  3. ֓ཁ w 3VCZͷܕղੳػೳ w 3VCZͱܕͷྺ࢙ w ܕݕࠪπʔϧͷ։ൃͷ༷ʑͳଆ໘

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

    ܕݕࠪث͸ಉࠝͳ͠
  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
  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)
  7. 3#4 w 3VCZίʔυͱ͸ผͷϑΝΠϧʹهड़ w 3VCZͱͷ׬ᘳͳޓ׵ੑ w 3VCZίʔυʹܕ஫ऍΛೖΕͳ͍ͱ͍͏ͩ͜ΘΓ w ͲΜͳ3VCZϓϩάϥϜͰ΋ɺ3#4͕ॻ͚Ε͹ܕ͕ॻ͚Δ

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

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

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

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

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

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

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

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

     .-ͷܕਪ࿦ʹجͮ͘΋ͷʢদຊ ೆग़ʣ ϑϩʔղੳʹجͮ͘΋ͷʢদຊ ೆग़ʣ %JBNPOECBDL3VCZʢ'VSS 'PTUFSʣ 4UFFQʢদຊʣ 4PSCFU 4USJQF 5ZQF1SPGʢԕ౻ʣ NNDʢࡾӜʣ +VTUJO5JNF4UBUJD5ZQF$IFDLJOHGPS 
 %ZOBNJD-BOHVBHFTʢ3FO 'PTUFSʣ
  17. 3VCZʹ޲͚ͯ     4UFFQʢদຊʣ 4PSCFU 4USJQF 5ZQF1SPGʢԕ౻ʣ NNDʢࡾӜʣ

    3VCZʹܕΛೖΕΔ͜ͱΛએݴ .BU[   3VCZʹܕݕࠪثΛೖΕͳ͍͜ͱΛܾఆ .BU[ 3#4ͷಋೖΛܾఆ .BU[ 5ZQF1SPGͷಋೖΛܾఆ .BU[ ౦๺େֶిؾ௨৴ݚڀॴڞಉϓϩδΣΫτ SVCZUZQFTNFFUJOH
  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
  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
  20. ֓ཁ w 3VCZͷܕղੳػೳ w 3VCZͱܕͷྺ࢙ w ܕݕࠪπʔϧͷ։ൃͷ༷ʑͳଆ໘

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

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

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

    ... when Numeric ... when Array ... end
  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 # => 💣
  25. ༷ʑͳࠔ೉ w ੍໿ɿطଘͷ3VCZίʔυ͕Ͱ͖Δ͚ͩܕݕࠪͰ͖ͯཉ͍͠ w 3VCZʹܕ஫ऍΛೖΕΔ͜ͱ͸Ͱ͖ͳ͍ʢ.BU[ܾఆʣ w ͍Ζ͍ΖͱఘΊΔ͔͠ͳ͔ͬͨ ࣗ༝ͳΦʔόʔϥΠυ $PWBSJBOUͳίϨΫγϣϯ 'MPXTFOTJUJWFͳղੳ

    ഑ྻͷΞΫηε ϝλϓϩάϥϛϯάʹΑΔఆٛ
  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
  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
  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ʁ
  29. ྑ͍ํ๏͸ͳ͍͔ʁ w +BWBͷΑ͏ʹ΍Δͷ͸Ͳ͏͔ʁ w ಛผͳ(FOFSJDTͷߏจͰɺҾ਺ʹܕม਺͕ग़ͯ͘ΔϝιουΛফ͢ def read_array: (Array[? extends Object])

    -> void class Array[Elem] def []: (Integer) -> Elem # ࢒͢ def <<: (Elem) -> Array[Elem] # ফ͢ end
  30. class Array[Elem] def find: (Elem) -> Elem? end

  31. class Array[Elem] def find: (Elem) -> Elem? end class Array[Elem]

    def find: (top) -> Elem? end
  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
  33. ఘΊͨ w ഑ྻͷཁૉ͸$PWBSJBOUͩͱܾΊͨ w ੈͷதͦ͏͍͏͜ͱʹͳ͍ͬͯΔʢ+BWB΋5ZQF4DSJQU΋ͦ͏ʣ class Array[unchecked out Elem] def

    <<: (Elem) -> Array[Elem] def pop: () -> Elem? # ͦ΋ͦ΋pop͕μϝ end
  34. ܕఆٛͷςετ w ϥΠϒϥϦͷܕΛॻ͍ͯཉ͍͠ w ܕݕࠪثͳ͠ͰܕΛॻ͘ͷ͸ແཧ w 4UFFQΛ࢖͏ͷ͸ͦΕͳΓʹେม w ૊ΈࠐΈϥΠϒϥϦͷιʔείʔυ͸$ w

    ॻ͍ͨܕͷਖ਼͠͞ΛͳΜͱͳ֬͘ೝ͢Δํ๏͕ඞཁ
  35. ܕఆٛͷςετ w ࣮ߦ࣌ݕࠪͱ૊Έ߹ΘͤΔํ๏ʢ૊ΈࠐΈϥΠϒϥϦͰ࢖༻ʣ w 4UFFQΛ࢖͏ํ๏ʢHFN@SCT@DPMMFDUJPOͰ࢖༻ʣ w ґଘ͕͋ΔͷͰɺςετ࣮ߦ͕ࠔ೉ w ظ଴͞ΕΔܕΤϥʔΛอଘ͓͍ͯͯ͠ൺֱ #

    io.read(0) assert_send_type "(Integer) -> String", io, :read, 0 $ steep check --with-expectations=test.yml
  36. *%&࿈ܞͷ։ൃ w 4UFFQͷ*%&࿈ܞػೳ w -BOHVBHF4FSWFS1SPUPDPMΛར༻ w Τϥʔใࠂɺิ׬ɺυΩϡϝϯτද ࣔɺఆٛʹδϟϯϓ w ࣮૷ɾௐ੔ʹແݶʹ͕͔͔࣌ؒΔ

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

  38. ิ׬ީิͷੜ੒ foo.ba← ͜͜ʂ foo.← ͜͜ʂ w ͜Ε͸ਖ਼͍͠3VCZίʔυ w ܕݕࠪͯ͠ɺΧʔιϧҐஔͷࣜͷܕ ͔Βิ׬ީิΛੜ੒

    w ͜Ε͸ߏจΤϥʔ w Χʔιϧͷલ͕ͩͬͨΒɺҰจࣈ ফͯ͠Έͯɺߏจղੳ w ղੳͰ͖ͨΒͦͷܕ৘ใ͔Βิ׬ w ҙ֎ͱྑ͍ײ͡Ͱಈ͘
  39. ީิੜ੒଎౓ͷ޲্ w ίʔυ͕௕͍ʢߦͱ͔ʣͱܕݕ͕ࠪ஗͍ʢ໨ඪ͸ඵʣ 
 㱺ؔ܎ͳ͍෦෼Λফ͔ͯ͠Βܕݕࠪ͢Δ class Foo include Bar def

    foo f # ͜͜Ͱิ׬ end def bar ... end w 4UFFQͷܕݕࠪʹ͸࠷΋಺ଆͷEFG Ҏ֎͸ؔ܎ͳ͍ w ϝιουͷܕ͸3#4͔ΒಡΉ w Ωϟογϡͷঢ়گʹ΋ΑΔ͕ɺ࠷ ѱͰඵ͘Β͍
  40. ·ͱΊ w 3VCZͷܕղੳػೳͷ঺հ w 3VCZ޲͚ͷܕݕࠪπʔϧ͸࣮༻తͳ΋ͷ͕ग़͖͍ͯͯΔ w ༷ʑͳϓϩάϥϛϯάݴޠͰͷ੍ݶɾଥڠΛͦͷ··Ҿ͖ܧ͍Ͱ͍Δ w ϓϩάϥϚͷೲಘײ͕ࢦ਑ w

    ܕݕࠪثͷ࣮૷Ҏ֎ʹ΍Δ͜ͱ͕๲େʹ͋Δ
  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 HFN@SCT@DPMMFDUJPOIUUQTHJUIVCDPNSVCZHFN@SCT@DPMMFDUJPO