Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
型なし言語のための型
Search
Soutaro Matsumoto
November 03, 2019
Programming
7
13k
型なし言語のための型
富山Ruby会議01
Soutaro Matsumoto
November 03, 2019
Tweet
Share
More Decks by Soutaro Matsumoto
See All by Soutaro Matsumoto
Rubyの標準添付ライブラリを開発する
soutaro
2
140
Embedding it into Ruby code
soutaro
4
18k
Parsing RBS
soutaro
0
1.4k
Ruby programming with types in action
soutaro
4
860
IDE Development with Ruby
soutaro
4
1k
Ruby 3の新機能としての静的型検査の開発
soutaro
4
7.1k
An Introduction to Static Typing in Ruby 3
soutaro
3
380
The State of Ruby 3 Typing
soutaro
0
680
Ruby3 is a typed language
soutaro
0
350
Other Decks in Programming
See All in Programming
[JAWS-UG横浜 #76] イケてるアップデートを宇宙いち早く紹介するよ!
maroon1st
0
480
Mermaid x AST x 生成AI = コードとドキュメントの完全同期への道
shibuyamizuho
0
160
Scalaから始めるOpenFeature入門 / Scalaわいわい勉強会 #4
arthur1
1
340
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
テストコード書いてみませんか?
onopon
2
130
テストコード文化を0から作り、変化し続けた組織
kazatohiei
2
1.5k
20年もののレガシープロダクトに 0からPHPStanを入れるまで / phpcon2024
hirobe1999
0
500
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
840
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
4
290
わたしの星のままで一番星になる ~ 出産を機にSIerからEC事業会社に転職した話 ~
kimura_m_29
0
180
menu基盤チームによるGoogle Cloudの活用事例~Application Integration, Cloud Tasks編~
yoshifumi_ishikura
0
110
コンテナをたくさん詰め込んだシステムとランタイムの変化
makihiro
1
140
Featured
See All Featured
Scaling GitHub
holman
458
140k
Visualization
eitanlees
146
15k
Reflections from 52 weeks, 52 projects
jeffersonlam
347
20k
A Tale of Four Properties
chriscoyier
157
23k
Done Done
chrislema
181
16k
Building Your Own Lightsaber
phodgson
103
6.1k
4 Signs Your Business is Dying
shpigford
181
21k
[RailsConf 2023] Rails as a piece of cake
palkan
53
5k
Docker and Python
trallard
42
3.1k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
48k
Six Lessons from altMBA
skipperchong
27
3.5k
Stop Working from a Prison Cell
hatefulcrawdad
267
20k
Transcript
ܕͳ͠ݴޠͷͨΊͷܕ দຊफଠ !TPVUBSP
@soutaro
@soutaro
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference () { (::Talk) -> void } -> self
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::String ::Conference () { (::Talk) -> void } -> self
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻ Ruby3ʹಉࠝ ͖ͳͷΛΠϯετʔϧ
3#4SVCZTJHOBUVSF w 3#4ΛಡΜͰɺΫϥεఆٛͷใΛॲཧ͢ΔϥΠϒϥϦ w ৄ͘͠དྷिͷ3VCZ)BDL$IBMMFOHF)PMJEBZͰ IUUQTSIDDPOOQBTTDPNFWFOU class Set[A] def initialize:
(_Each[A, untyped]) -> void | () -> void def intersection: (_Each[A, untyped]) -> self ... end
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
ܕͳ͠ݴޠͷͨΊͷܕ w ܕ w ίϯύΠϧ࣌ʹ໌͢Δࣜͷଐੑ w ͋ΔछͷޡΓΛݕग़Ͱ͖Δʢܕݕࠪʣ w ܕͳ͠ݴޠ w
ίϯύΠϧ࣌ʹܕݕࠪ͞Εͳ͍ݴޠʢ㲈ಈతܕ͚ݴޠʣ w 3VCZͱ͔
ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ
class Person def name @name end def name=(value) @name =
value end end if rand(10) < 5 person = Person.new person.nme = "Soutaro Matsumoto" # NoMethodError end w ܕݕࠪʹΑͬͯɺཏతʹʢJGͷதʣݕࠪ͞Εͯɺ࣮ ߦલʹ͕ݕग़͞ΕΔʢίϯύΠϧ࣌ʣ w ܕݕࠪ͠ͳ͍߹ʹɺϓϩάϥϜͷ࣮ߦঢ়گʹΑͬ ͯɺ͕ݟ͔ͭΒͳ͍ʢ࣮ߦ࣌ʣ
ܕݕࠪͷಘࣦ w ͕ࣄલʹݕग़Ͱ͖Δ w ཏతͳݕࠪʢ࣮ߦͷύεʹґଘ͠ͳ͍ʣ w ॻ͚ΔϓϩάϥϜʹ੍ݶ͕ՃΘΔ w ࣮ࡍʹ࣮ߦ͞Εͳ͍ύεʹ͍ͭͯݕࠪ͞Εͯ͠·͏
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
.-ͷܕਪ w ʮ࠙ஸೡʹશ෦ͷࣜʹܕΛॻ͔ͳͯ͘ྑ͍ʯͱ͍͏ൃݟ w ύϥϝʔλଟ૬ʢେମ(FOFSJDTͷ͜ͱʣ # let rec map f
xs = match xs with [] -> [] | x::xs -> f x :: map f xs;; val map : ('a -> 'b) -> 'a list -> 'b list = <fun>
4PGU5ZQJOH w ܕͳ͠ͷݴޠʹܕΛ͚͍ͨ w ܕ͕͍ͭͨ෦Τϥʔ͕ݕग़Ͱ͖Δ w Θ͔Βͳ͍ͷ࣮ߦ࣌ʹݕࠪ͢Δ w ಈ͘ϓϩάϥϜͰ͖Δ͚ͩͦͷ··ܕݕࠪΛ௨͍ͨ͠ w
ܕऍઈରॻ͖ͨ͘ͳ͍
6OJPOUZQFT def f(x) if x 1 else "2" end end
6OJPOUZQFT def f(x) if x 1 else "2" end end
(bool) -> (Integer | String)
'MPXTFOTJUJWF5ZQJOH def g(n) n.abs # NoMethodError n.bytes # n: Integer
| String case n when Integer n.abs # n: Integer when String n.bytes # n: String end end (Integer | String) -> Integer
4PGU5ZQJOH w 4DIFNFϓϩάϥϜͷܕ͚ʹඞཁͳͷ͕Θ͔ͬͨ w 6OJPOUZQFT 'MPXTFOTJUJWFUZQJOH w ࣮ w
.-ͷܕਪʹجͮ͘ͷ w ϑϩʔղੳ͢Δͷ
ͬͱۙతͳݴޠͰʁ w +BWB4DSJQUͱ͔3VCZͱ͔< > w ΦϒδΣΫτʹର͢Δଟ૬ੑ BLBμοΫλΠϐϯά w ʮ͋Δϝιου͕ఆٛ͞Ε͍ͯΔҙͷΫϥεʯΈ͍ͨͳܕ
def add(x, y) x + y end def add: [A, B] ({ +: (A) -> B }, A) -> B
3VCZͰࢼͨ͠ͱ͜Ζ w ͬͺΓݫ͍͠ w .-ͷܕਪͰॲཧͰ͖ͳ͍ఆ͕ٛͰͯ͘Δ "SSBZNBQ w Ϋϥεఆ໋͕ٛྩతʹมΘ͍ͬͯ͘ͷ͕ݫ͍͠ʢϝλϓϩάϥϛϯάʣ w
ͦͦյΕ͍ͯΔఆ͕ٛͨ͘͞Μ͋Δ w "SSBZTFMFDUWT0CKFDUTFMFDU w )BTIΛฦ͢IBTIΛఆٛͨ͜͠ͱ͕ͳ͍ਓ
"SSBZJTB0CKFDU w 0CKFDUʹରͯ͠ಈ͘ϓϩάϥϜ"SSBZʹରͯ͠ಈ͘ʁʁ class Object def use_select select [STDIN], [],
[] end end "".use_select # OK [1,2,3].use_select # ????
4PGU5ZQJOH͔ΒಘΒΕͨݟ w จͰޭ͍ͯ͠ΔΑ͏ʹݟ͑Δ͕࣮༻Ϩϕϧͷͷͳ͍ w ඞཁͦ͏ͳܕγεςϜͷػೳΘ͔͖ͬͯͨ w Ή͠ΖܕΛॻ͍ͨํ͕ྑ͍ͷͰʁʁ w ϓϩάϥϚͷҙਤΛܕͰදݱ͢Δ w
ҙਤͱҰக͠ͳ͍ίʔυΛݕग़͢Δ
(SBEVBM5ZQJOH w ਐతܕ͚ w ܕͳ͠ͷίʔυͱܕ͖ͭͷίʔυΛࠞͥΔ w ͩΜͩΜܕΛ͚͍ͯ͘ w ܕॻ͘
ܕͳ͠ݴޠͷͨΊͷܕ w ͦΕͳΓʹڧྗͳܕγεςϜ w 6OJPOUZQFT qPXTFOTJUJWFUZQJOH HFOFSJDT w μοΫλΠϐϯά
w ߏత෦ܕ w ΫϥεͷܧঝؔΛ͋ͱͰมߋͰ͖ΔΈ )BTLFMM 4XJGU $ w (SBEVBM5ZQJOH
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
࠷ۙͷྲྀߦ w ܕ͖ͭͷํݴ w 5ZQF4DSJQU 5ZQFE4DIFNF w ܕऍͷαϙʔτ w 1ZUIPO
1)1
5ZQF4DSJQU w ݱࡏͰҰ൪উ͍ͬͯΔܕ͖ͭํݴ w λʔήοτݴޠ+4ʢϥϯλΠϜ+4ʣ class Drawer<ClothingType> { contents: ClothingType[]
= []; add(object: ClothingType) { this.contents.push(object); } } interface Sock { color: string } interface TShirt { size: "s" | "m" | "l" } const drawer: Drawer<Sock> = new Drawer() drawer.push({ color: "white" }) drawer.push({ size: "s" })
5ZQF4DSJQUͷ͍͢͝ͱ͜Ζ w ܕͳ͠ݴޠʹܕΛ͚Δਓྨͷເ͕ͬͨ w ΈΜͳܕΛॻ͍͍ͯΔͷ͕͍͢͝ w ߏతͳܕ͚ͩͰͳΜͱ͔ͳͬͯΔͷ͕͍͢͝ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQFTͱ͔MPHJDBMUZQFTͱ͔͠Εͬͱ ೖͬͯΔͷ͕͍͢͝
w ϥϯλΠϜͱͷ੍ΛΓӽ͑ͯಈ͍ͯΔͷ͕͍͢͝
ܕॻ͔ͳ͍͚ͯ͘ͳ͍ w ΑͬΆͲࣗ໌ͳͷҎ֎ॻ͘ w ϥΠϒϥϦͷܕEFpOJUFMZUZQFEʹू·͍ͬͯΔ const numbers: number[] = [1,2,3]
numbers.map<string>(x => x.toString())
jQuery.d.ts
ߏతͳܕ w ΫϥεͷܧঝؔͰͳ͘ɺϝιουͷू߹Ͱ෦ܕؔΛఆ͢Δ w ߏతͳܕ͚ͩͱ͍͏ͷ͍͠ w ͋Δ interface ForEach<A> {
forEach: (fun: (a: A) => void) => void } const x: ForEach<number> = [1,2,3]
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; }
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; } interface TShirt { type: "tshirt" size: "s" | "m" | "l"; } interface Pants { type: "pants" size: "s" | "m" | "l"; }
6OJPO5ZQFT'MPXTFOTJUJWF5ZQJOH w OVMMVOEFpOFEͱ͏·͘ΕΔΑ͏ʹͳͬͨ const x: string | undefined = ...
// Object is possibly 'undefined'. x.toUpperCase() if (x) { x.toUpperCase() }
ϥϯλΠϜͷ੍ w +4ͷϥϯλΠϜʹͰ͖ͳ͍͜ͱ54ͰͰ͖ͳ͍ w ʮ͋Δ͕ΠϯλʔϑΣʔεʹద߹͍ͯ͠Δ͔ݕ͍ࠪͨ͠ʯ w Ϣʔβʔ͕ࣗͷͰݕূ͢Δ -PHJDBMUZQFT •
function isPants(object: any): object is Pants { return object.type == "pants" }
ݟ w ਓؒܕΛॻ͘ w ʢܕΛॻ͖ͨ͘ͳ͍ਓ5ZQF4DSJQUΛΘͳ͍ͷͰ؍ଌͰ͖ͳ͍ʣ w େମ+BWB4DSJQUͷίʔυʹܕ͕ͭ͘ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQJOHͱ͔͕ॏཁ w
ߏత෦ܕಈ͘ w ϥϯλΠϜͷ੍ݶΛΓӽ͑ΔͨΊ JTܕ
1ZUIPO 1)1 w ϝιουͷܕΛॻ͘ه๏͕ಋೖ͞Εͨ w ܕݕ࣮ࠪߦ࣌ w ϝιουݺͼग़͠ͷͱ͖ʹܕݕࠪ͢Δ w ੩తͳܕݕࠪث։ൃ͞Ε͍ͯΔ
function sum(int $a, int $b) { return $a + $b; }
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
3VCZͷͨΊͷܕ w 4PGUUZQJOHͷݟˠਪΛؤுΔͷઓతʢ!NBNFʣ w 5ZQF4DSJQUͷݟ w ਓྨܕΛॻ͘ w ͦΕͳΓʹڧྗͳܕγεςϜ͕͋Ε্ख͘Εͦ͏ w
1ZUIPO 1)1ͷݟ w ܕऍܾΊͳ͍ͱ͍͚ͳ͍ w ܕݕࠪثผπʔϧʹ͢Δ
ܕऍͷه๏ 3#4 w গͳ͘ͱϥΠϒϥϦͷܕΛॻ͘ํ๏͕ඞཁ w ܕݕࠪπʔϧ͕ͦΕͧΕʹ༻ҙ͢Δͷ͔ͳΓݫ͍͠ w ϥϯλΠϜͷݕ͕ࠪͰ͖Δ͚ͩͰͦΕͳΓʹخ͍͠Ͱʁ w ιʔείʔυʹຒΊࠐΉߏจ࠾༻͠ͳ͍
ΈࠐΈͷܕऍߏจʢෆ࠾༻ʣ class Box extend T::Sig extend T::Generic Elem = type_member
sig {returns(Elem)} # @type var box: Box[Integer] box = Box.new box.x = "hello" &NCFEEFE%4- 4PSCFU $PNNFOUT 4UFFQ class Box [A] def value: A; ...; end def value=(value: A): A; ...; end end a: Box[Integer] = Box.new
ͦΕͳΓʹϦονͳܕ w λϓϧɺϨίʔυ [Integer, Symbol] w Ϧςϥϧܕ 1, "hello", :world
w 6OJPOUZQFT Integer | String w 0QUJPOBMUZQFTɺ(FOFSJDTʜ Array[String]? w յΕ͍ͯΔͷJODPNQBUJCMF incompatible def select: [A] () { (Elem) -> A
μοΫλΠϐϯά w JOUFSGBDFΛఆٛͯ͠ɺཁٻ͞ΕΔϝιουͷू߹Λॻ͘ w ϝιου͕͋Δ͔ͳ͍͔Ͱݕࠪ͞ΕΔ interface _Push def <<: (String)
-> void end def foo: (_Push) -> void def foo(a) a << "hello" end foo [] foo "" foo 3 # Τϥʔ
࣮ߦ࣌ݕ͚ࠪͩͰ w γάωνϟΛॻ͍ͨΒɺϢχοτςετͰςετ͢Δํ๏Λఏڙ w ϝιουݺͼग़͠ͷલޙʹܕݕࠪΛૠೖ w IUUQTSIDDPOOQBTTDPNFWFOU $ RBS_TEST_TARGET='Goodcheck::*' \
RBS_TEST_RAISE=true \ RUBYOPT='-rbundler/setup -rruby/signature/test/setup' \ RBS_TEST_OPT='-rset -rpathname -Isig' \ bundle exec rake test
IUUQTHJUIVCDPNTJEFSHPPEDIFDLUSFFSCT
·ͱΊ w 4PGUUZQJOHΈ͍ͨʹਪΛؤுΔͷ߹ཧతͰͳ͍ w ܕΛॻ͔ͳ͍ͷݫ͍͠ w ਓؒܕΛॻ͘ʢ͜͜ͰಘΒΕͨݟʣ w 3VCZͷͨΊͷܕ w
ΘΓͱϦονͳܕ(FOFSJDTɺ6OJPOUZQFTɺ'MPXTFOTJUJWFUZQJOH w μοΫλΠϐϯάؤுΔʢߏత෦ܕʣ
w <$BSUXSJHIU >3$BSUXSJHIUBOE.'BHBO4PGUUZQJOH w <.BUTVNPUP >4.BUTVNPUPBOE:.JOBNJEF5ZQF*OGFSFODFGPS3VCZ 1SPHSBNTCBTFEPO1PMZNPSQIJD3FDPSE5ZQFT w <+FOTFO >4)+FOTFOBOE".MMFSBOE15IJFNBOO
5ZQF"OBMZTJTGPS +BWB4DSJQU w <4JFL >+4JFLBOE85BIB (SBEVBM5ZQJOHGPS0CKFDUT w <)PDITUBEU >45)PDITUBEU 5ZQFE4DIFNF'SPN4DSJQUTUP1SPHSBNT w